Merge branch 'migrate_to_bullseye' into bullseye

This commit is contained in:
Alexandre Aubin 2021-09-21 16:04:32 +02:00
commit ae08698253
101 changed files with 6459 additions and 2320 deletions

View file

@ -18,6 +18,13 @@ invalidcode39:
script: script:
- tox -e py39-invalidcode - tox -e py39-invalidcode
mypy:
stage: lint
image: "before-install"
needs: []
script:
- tox -e py37-mypy
format-check: format-check:
stage: lint stage: lint
image: "before-install" image: "before-install"

View file

@ -71,7 +71,7 @@ test-translation-format-consistency:
test-actionmap: test-actionmap:
extends: .test-stage extends: .test-stage
script: script:
- python3 -m pytest tests tests/test_actionmap.py - python3 -m pytest tests/test_actionmap.py
only: only:
changes: changes:
- data/actionsmap/*.yml - data/actionsmap/*.yml
@ -85,11 +85,27 @@ test-helpers:
changes: changes:
- data/helpers.d/* - data/helpers.d/*
test-domains:
extends: .test-stage
script:
- python3 -m pytest src/yunohost/tests/test_domains.py
only:
changes:
- src/yunohost/domain.py
test-dns:
extends: .test-stage
script:
- python3 -m pytest src/yunohost/tests/test_dns.py
only:
changes:
- src/yunohost/dns.py
- src/yunohost/utils/dns.py
test-apps: test-apps:
extends: .test-stage extends: .test-stage
script: script:
- cd src/yunohost - python3 -m pytest src/yunohost/tests/test_apps.py
- python3 -m pytest tests/test_apps.py
only: only:
changes: changes:
- src/yunohost/app.py - src/yunohost/app.py
@ -97,8 +113,7 @@ test-apps:
test-appscatalog: test-appscatalog:
extends: .test-stage extends: .test-stage
script: script:
- cd src/yunohost - python3 -m pytest src/yunohost/tests/test_appscatalog.py
- python3 -m pytest tests/test_appscatalog.py
only: only:
changes: changes:
- src/yunohost/app.py - src/yunohost/app.py
@ -106,26 +121,32 @@ test-appscatalog:
test-appurl: test-appurl:
extends: .test-stage extends: .test-stage
script: script:
- cd src/yunohost - python3 -m pytest src/yunohost/tests/test_appurl.py
- python3 -m pytest tests/test_appurl.py
only: only:
changes: changes:
- src/yunohost/app.py - src/yunohost/app.py
test-apps-arguments-parsing: test-questions:
extends: .test-stage extends: .test-stage
script: script:
- cd src/yunohost - python3 -m pytest src/yunohost/tests/test_questions.py
- python3 -m pytest tests/test_apps_arguments_parsing.py only:
changes:
- src/yunohost/utils/config.py
test-app-config:
extends: .test-stage
script:
- python3 -m pytest src/yunohost/tests/test_app_config.py
only: only:
changes: changes:
- src/yunohost/app.py - src/yunohost/app.py
- src/yunohost/utils/config.py
test-changeurl: test-changeurl:
extends: .test-stage extends: .test-stage
script: script:
- cd src/yunohost - python3 -m pytest src/yunohost/tests/test_changeurl.py
- python3 -m pytest tests/test_changeurl.py
only: only:
changes: changes:
- src/yunohost/app.py - src/yunohost/app.py
@ -133,8 +154,7 @@ test-changeurl:
test-backuprestore: test-backuprestore:
extends: .test-stage extends: .test-stage
script: script:
- cd src/yunohost - python3 -m pytest src/yunohost/tests/test_backuprestore.py
- python3 -m pytest tests/test_backuprestore.py
only: only:
changes: changes:
- src/yunohost/backup.py - src/yunohost/backup.py
@ -142,8 +162,7 @@ test-backuprestore:
test-permission: test-permission:
extends: .test-stage extends: .test-stage
script: script:
- cd src/yunohost - python3 -m pytest src/yunohost/tests/test_permission.py
- python3 -m pytest tests/test_permission.py
only: only:
changes: changes:
- src/yunohost/permission.py - src/yunohost/permission.py
@ -151,8 +170,7 @@ test-permission:
test-settings: test-settings:
extends: .test-stage extends: .test-stage
script: script:
- cd src/yunohost - python3 -m pytest src/yunohost/tests/test_settings.py
- python3 -m pytest tests/test_settings.py
only: only:
changes: changes:
- src/yunohost/settings.py - src/yunohost/settings.py
@ -160,8 +178,7 @@ test-settings:
test-user-group: test-user-group:
extends: .test-stage extends: .test-stage
script: script:
- cd src/yunohost - python3 -m pytest src/yunohost/tests/test_user-group.py
- python3 -m pytest tests/test_user-group.py
only: only:
changes: changes:
- src/yunohost/user.py - src/yunohost/user.py
@ -169,8 +186,7 @@ test-user-group:
test-regenconf: test-regenconf:
extends: .test-stage extends: .test-stage
script: script:
- cd src/yunohost - python3 -m pytest src/yunohost/tests/test_regenconf.py
- python3 -m pytest tests/test_regenconf.py
only: only:
changes: changes:
- src/yunohost/regenconf.py - src/yunohost/regenconf.py
@ -178,8 +194,7 @@ test-regenconf:
test-service: test-service:
extends: .test-stage extends: .test-stage
script: script:
- cd src/yunohost - python3 -m pytest src/yunohost/tests/test_service.py
- python3 -m pytest tests/test_service.py
only: only:
changes: changes:
- src/yunohost/service.py - src/yunohost/service.py
@ -187,8 +202,7 @@ test-service:
test-ldapauth: test-ldapauth:
extends: .test-stage extends: .test-stage
script: script:
- cd src/yunohost - python3 -m pytest src/yunohost/tests/test_ldapauth.py
- python3 -m pytest tests/test_ldapauth.py
only: only:
changes: changes:
- src/yunohost/authenticators/*.py - src/yunohost/authenticators/*.py

View file

@ -20,7 +20,7 @@ autofix-translated-strings:
- python3 reformat_locales.py - python3 reformat_locales.py
- '[ $(git diff -w | wc -l) != 0 ] || exit 0' # stop if there is nothing to commit - '[ $(git diff -w | wc -l) != 0 ] || exit 0' # stop if there is nothing to commit
- git commit -am "[CI] Reformat / remove stale translated strings" || true - git commit -am "[CI] Reformat / remove stale translated strings" || true
- git push -f origin "ci-remove-stale-translated-strings-${CI_COMMIT_REF_NAME}":"ci-remove-stale-translated-strings-${CI_COMMIT_REF_NAME}" - git push -f origin "HEAD":"ci-remove-stale-translated-strings-${CI_COMMIT_REF_NAME}"
- hub pull-request -m "[CI] Reformat / remove stale translated strings" -b Yunohost:dev -p || true # GITHUB_USER and GITHUB_TOKEN registered here https://gitlab.com/yunohost/yunohost/-/settings/ci_cd - hub pull-request -m "[CI] Reformat / remove stale translated strings" -b Yunohost:dev -p || true # GITHUB_USER and GITHUB_TOKEN registered here https://gitlab.com/yunohost/yunohost/-/settings/ci_cd
only: only:
variables: variables:

View file

@ -476,21 +476,17 @@ domain:
help: Do not ask confirmation to remove apps help: Do not ask confirmation to remove apps
action: store_true action: store_true
### domain_dns_conf() ### domain_dns_conf()
dns-conf: dns-conf:
deprecated: true
action_help: Generate sample DNS configuration for a domain action_help: Generate sample DNS configuration for a domain
api: GET /domains/<domain>/dns
arguments: arguments:
domain: domain:
help: Target domain help: Target domain
-t:
full: --ttl
help: Time To Live (TTL) in second before DNS servers update. Default is 3600 seconds (i.e. 1 hour).
extra: extra:
pattern: pattern: *pattern_domain
- !!str ^[0-9]+$
- "pattern_positive_number"
### domain_maindomain() ### domain_maindomain()
main-domain: main-domain:
action_help: Check the current main domain, or change it action_help: Check the current main domain, or change it
@ -508,8 +504,8 @@ domain:
### certificate_status() ### certificate_status()
cert-status: cert-status:
deprecated: true
action_help: List status of current certificates (all by default). action_help: List status of current certificates (all by default).
api: GET /domains/<domain_list>/cert
arguments: arguments:
domain_list: domain_list:
help: Domains to check help: Domains to check
@ -520,8 +516,8 @@ domain:
### certificate_install() ### certificate_install()
cert-install: cert-install:
deprecated: true
action_help: Install Let's Encrypt certificates for given domains (all by default). action_help: Install Let's Encrypt certificates for given domains (all by default).
api: PUT /domains/<domain_list>/cert
arguments: arguments:
domain_list: domain_list:
help: Domains for which to install the certificates help: Domains for which to install the certificates
@ -541,8 +537,8 @@ domain:
### certificate_renew() ### certificate_renew()
cert-renew: cert-renew:
deprecated: true
action_help: Renew the Let's Encrypt certificates for given domains (all by default). action_help: Renew the Let's Encrypt certificates for given domains (all by default).
api: PUT /domains/<domain_list>/cert/renew
arguments: arguments:
domain_list: domain_list:
help: Domains for which to renew the certificates help: Domains for which to renew the certificates
@ -572,6 +568,141 @@ domain:
path: path:
help: The path to check (e.g. /coffee) help: The path to check (e.g. /coffee)
subcategories:
config:
subcategory_help: Domain settings
actions:
### domain_config_get()
get:
action_help: Display a domain configuration
api: GET /domains/<domain>/config
arguments:
domain:
help: Domain name
key:
help: A specific panel, section or a question identifier
nargs: '?'
-f:
full: --full
help: Display all details (meant to be used by the API)
action: store_true
-e:
full: --export
help: Only export key/values, meant to be reimported using "config set --args-file"
action: store_true
### domain_config_set()
set:
action_help: Apply a new configuration
api: PUT /domains/<domain>/config
arguments:
domain:
help: Domain name
key:
help: The question or form key
nargs: '?'
-v:
full: --value
help: new value
-a:
full: --args
help: Serialized arguments for new configuration (i.e. "mail_in=0&mail_out=0")
dns:
subcategory_help: Manage domains DNS
actions:
### domain_dns_conf()
suggest:
action_help: Generate sample DNS configuration for a domain
api:
- GET /domains/<domain>/dns
- GET /domains/<domain>/dns/suggest
arguments:
domain:
help: Target domain
extra:
pattern: *pattern_domain
### domain_dns_push()
push:
action_help: Push DNS records to registrar
api: POST /domains/<domain>/dns/push
arguments:
domain:
help: Domain name to push DNS conf for
extra:
pattern: *pattern_domain
-d:
full: --dry-run
help: Only display what's to be pushed
action: store_true
--force:
help: Also update/remove records which were not originally set by Yunohost, or which have been manually modified
action: store_true
--purge:
help: Delete all records
action: store_true
cert:
subcategory_help: Manage domain certificates
actions:
### certificate_status()
status:
action_help: List status of current certificates (all by default).
api: GET /domains/<domain_list>/cert
arguments:
domain_list:
help: Domains to check
nargs: "*"
--full:
help: Show more details
action: store_true
### certificate_install()
install:
action_help: Install Let's Encrypt certificates for given domains (all by default).
api: PUT /domains/<domain_list>/cert
arguments:
domain_list:
help: Domains for which to install the certificates
nargs: "*"
--force:
help: Install even if current certificate is not self-signed
action: store_true
--no-checks:
help: Does not perform any check that your domain seems correctly configured (DNS, reachability) before attempting to install. (Not recommended)
action: store_true
--self-signed:
help: Install self-signed certificate instead of Let's Encrypt
action: store_true
--staging:
help: Use the fake/staging Let's Encrypt certification authority. The new certificate won't actually be enabled - it is only intended to test the main steps of the procedure.
action: store_true
### certificate_renew()
renew:
action_help: Renew the Let's Encrypt certificates for given domains (all by default).
api: PUT /domains/<domain_list>/cert/renew
arguments:
domain_list:
help: Domains for which to renew the certificates
nargs: "*"
--force:
help: Ignore the validity threshold (30 days)
action: store_true
--email:
help: Send an email to root with logs if some renewing fails
action: store_true
--no-checks:
help: Does not perform any check that your domain seems correctly configured (DNS, reachability) before attempting to renew. (Not recommended)
action: store_true
--staging:
help: Use the fake/staging Let's Encrypt certification authority. The new certificate won't actually be enabled - it is only intended to test the main steps of the procedure.
action: store_true
############################# #############################
# App # # App #
############################# #############################
@ -811,24 +942,45 @@ app:
subcategory_help: Applications configuration panel subcategory_help: Applications configuration panel
actions: actions:
### app_config_show_panel() ### app_config_get()
show-panel: get:
action_help: show config panel for the application action_help: Display an app configuration
api: GET /apps/<app>/config-panel api: GET /apps/<app>/config-panel
arguments: arguments:
app: app:
help: App name help: App name
key:
help: A specific panel, section or a question identifier
nargs: '?'
-f:
full: --full
help: Display all details (meant to be used by the API)
action: store_true
-e:
full: --export
help: Only export key/values, meant to be reimported using "config set --args-file"
action: store_true
### app_config_apply() ### app_config_set()
apply: set:
action_help: apply the new configuration action_help: Apply a new configuration
api: PUT /apps/<app>/config api: PUT /apps/<app>/config
arguments: arguments:
app: app:
help: App name help: App name
-a: key:
full: --args help: The question or panel key
help: Serialized arguments for new configuration (i.e. "domain=domain.tld&path=/path") nargs: '?'
-v:
full: --value
help: new value
-a:
full: --args
help: Serialized arguments for new configuration (i.e. "domain=domain.tld&path=/path")
-f:
full: --args-file
help: YAML or JSON file with key/value couples
type: open
############################# #############################
# Backup # # Backup #

View file

@ -13,6 +13,7 @@ import yaml
THIS_SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) THIS_SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
ACTIONSMAP_FILE = THIS_SCRIPT_DIR + "/yunohost.yml" ACTIONSMAP_FILE = THIS_SCRIPT_DIR + "/yunohost.yml"
os.system(f"mkdir {THIS_SCRIPT_DIR}/../bash-completion.d")
BASH_COMPLETION_FILE = THIS_SCRIPT_DIR + "/../bash-completion.d/yunohost" BASH_COMPLETION_FILE = THIS_SCRIPT_DIR + "/../bash-completion.d/yunohost"

View file

@ -1,3 +0,0 @@
# This file is automatically generated
# during Debian's package build by the script
# data/actionsmap/yunohost_completion.py

View file

@ -313,12 +313,25 @@ ynh_restore_file () {
ynh_store_file_checksum () { ynh_store_file_checksum () {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=f local legacy_args=f
local -A args_array=( [f]=file= ) local -A args_array=( [f]=file= [u]=update_only )
local file local file
local update_only
update_only="${update_only:-0}"
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
local checksum_setting_name=checksum_${file//[\/ ]/_} # Replace all '/' and ' ' by '_' local checksum_setting_name=checksum_${file//[\/ ]/_} # Replace all '/' and ' ' by '_'
# If update only, we don't save the new checksum if no old checksum exist
if [ $update_only -eq 1 ] ; then
local checksum_value=$(ynh_app_setting_get --app=$app --key=$checksum_setting_name)
if [ -z "${checksum_value}" ] ; then
unset backup_file_checksum
return 0
fi
fi
ynh_app_setting_set --app=$app --key=$checksum_setting_name --value=$(md5sum "$file" | cut --delimiter=' ' --fields=1) ynh_app_setting_set --app=$app --key=$checksum_setting_name --value=$(md5sum "$file" | cut --delimiter=' ' --fields=1)
# If backup_file_checksum isn't empty, ynh_backup_if_checksum_is_different has made a backup # If backup_file_checksum isn't empty, ynh_backup_if_checksum_is_different has made a backup

328
data/helpers.d/config Normal file
View file

@ -0,0 +1,328 @@
#!/bin/bash
_ynh_app_config_get() {
# From settings
local lines
lines=$(python3 << EOL
import toml
from collections import OrderedDict
with open("../config_panel.toml", "r") as f:
file_content = f.read()
loaded_toml = toml.loads(file_content, _dict=OrderedDict)
for panel_name, panel in loaded_toml.items():
if not isinstance(panel, dict): continue
for section_name, section in panel.items():
if not isinstance(section, dict): continue
for name, param in section.items():
if not isinstance(param, dict):
continue
print(';'.join([
name,
param.get('type', 'string'),
param.get('bind', 'settings' if param.get('type', 'string') != 'file' else 'null')
]))
EOL
)
for line in $lines
do
# Split line into short_setting, type and bind
IFS=';' read short_setting type bind <<< "$line"
local getter="get__${short_setting}"
binds[${short_setting}]="$bind"
types[${short_setting}]="$type"
file_hash[${short_setting}]=""
formats[${short_setting}]=""
# Get value from getter if exists
if type -t $getter 2>/dev/null | grep -q '^function$' 2>/dev/null;
then
old[$short_setting]="$($getter)"
formats[${short_setting}]="yaml"
elif [[ "$bind" == "null" ]]
then
old[$short_setting]="YNH_NULL"
# Get value from app settings or from another file
elif [[ "$type" == "file" ]]
then
if [[ "$bind" == "settings" ]]
then
ynh_die --message="File '${short_setting}' can't be stored in settings"
fi
old[$short_setting]="$(ls "$(echo $bind | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)" 2> /dev/null || echo YNH_NULL)"
file_hash[$short_setting]="true"
# Get multiline text from settings or from a full file
elif [[ "$type" == "text" ]]
then
if [[ "$bind" == "settings" ]]
then
old[$short_setting]="$(ynh_app_setting_get $app $short_setting)"
elif [[ "$bind" == *":"* ]]
then
ynh_die --message="For technical reasons, multiline text '${short_setting}' can't be stored automatically in a variable file, you have to create custom getter/setter"
else
old[$short_setting]="$(cat $(echo $bind | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/) 2> /dev/null || echo YNH_NULL)"
fi
# Get value from a kind of key/value file
else
local bind_after=""
if [[ "$bind" == "settings" ]]
then
bind=":/etc/yunohost/apps/$app/settings.yml"
fi
local bind_key="$(echo "$bind" | cut -d: -f1)"
bind_key=${bind_key:-$short_setting}
if [[ "$bind_key" == *">"* ]];
then
bind_after="$(echo "${bind_key}" | cut -d'>' -f1)"
bind_key="$(echo "${bind_key}" | cut -d'>' -f2)"
fi
local bind_file="$(echo "$bind" | cut -d: -f2 | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
old[$short_setting]="$(ynh_read_var_in_file --file="${bind_file}" --key="${bind_key}" --after="${bind_after}")"
fi
done
}
_ynh_app_config_apply() {
for short_setting in "${!old[@]}"
do
local setter="set__${short_setting}"
local bind="${binds[$short_setting]}"
local type="${types[$short_setting]}"
if [ "${changed[$short_setting]}" == "true" ]
then
# Apply setter if exists
if type -t $setter 2>/dev/null | grep -q '^function$' 2>/dev/null;
then
$setter
elif [[ "$bind" == "null" ]]
then
continue
# Save in a file
elif [[ "$type" == "file" ]]
then
if [[ "$bind" == "settings" ]]
then
ynh_die --message="File '${short_setting}' can't be stored in settings"
fi
local bind_file="$(echo "$bind" | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
if [[ "${!short_setting}" == "" ]]
then
ynh_backup_if_checksum_is_different --file="$bind_file"
ynh_secure_remove --file="$bind_file"
ynh_delete_file_checksum --file="$bind_file" --update_only
ynh_print_info --message="File '$bind_file' removed"
else
ynh_backup_if_checksum_is_different --file="$bind_file"
if [[ "${!short_setting}" != "$bind_file" ]]
then
cp "${!short_setting}" "$bind_file"
fi
ynh_store_file_checksum --file="$bind_file" --update_only
ynh_print_info --message="File '$bind_file' overwrited with ${!short_setting}"
fi
# Save value in app settings
elif [[ "$bind" == "settings" ]]
then
ynh_app_setting_set --app=$app --key=$short_setting --value="${!short_setting}"
ynh_print_info --message="Configuration key '$short_setting' edited in app settings"
# Save multiline text in a file
elif [[ "$type" == "text" ]]
then
if [[ "$bind" == *":"* ]]
then
ynh_die --message="For technical reasons, multiline text '${short_setting}' can't be stored automatically in a variable file, you have to create custom getter/setter"
fi
local bind_file="$(echo "$bind" | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
ynh_backup_if_checksum_is_different --file="$bind_file"
echo "${!short_setting}" > "$bind_file"
ynh_store_file_checksum --file="$bind_file" --update_only
ynh_print_info --message="File '$bind_file' overwrited with the content you provieded in '${short_setting}' question"
# Set value into a kind of key/value file
else
local bind_after=""
local bind_key="$(echo "$bind" | cut -d: -f1)"
bind_key=${bind_key:-$short_setting}
if [[ "$bind_key" == *">"* ]];
then
bind_after="$(echo "${bind_key}" | cut -d'>' -f1)"
bind_key="$(echo "${bind_key}" | cut -d'>' -f2)"
fi
local bind_file="$(echo "$bind" | cut -d: -f2 | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
ynh_backup_if_checksum_is_different --file="$bind_file"
ynh_write_var_in_file --file="${bind_file}" --key="${bind_key}" --value="${!short_setting}" --after="${bind_after}"
ynh_store_file_checksum --file="$bind_file" --update_only
# We stored the info in settings in order to be able to upgrade the app
ynh_app_setting_set --app=$app --key=$short_setting --value="${!short_setting}"
ynh_print_info --message="Configuration key '$bind_key' edited into $bind_file"
fi
fi
done
}
_ynh_app_config_show() {
for short_setting in "${!old[@]}"
do
if [[ "${old[$short_setting]}" != YNH_NULL ]]
then
if [[ "${formats[$short_setting]}" == "yaml" ]]
then
ynh_return "${short_setting}:"
ynh_return "$(echo "${old[$short_setting]}" | sed 's/^/ /g')"
else
ynh_return "${short_setting}: "'"'"$(echo "${old[$short_setting]}" | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\n\n/g')"'"'
fi
fi
done
}
_ynh_app_config_validate() {
# Change detection
ynh_script_progression --message="Checking what changed in the new configuration..." --weight=1
local nothing_changed=true
local changes_validated=true
for short_setting in "${!old[@]}"
do
changed[$short_setting]=false
if [ -z ${!short_setting+x} ]
then
# Assign the var with the old value in order to allows multiple
# args validation
declare "$short_setting"="${old[$short_setting]}"
continue
fi
if [ ! -z "${file_hash[${short_setting}]}" ]
then
file_hash[old__$short_setting]=""
file_hash[new__$short_setting]=""
if [ -f "${old[$short_setting]}" ]
then
file_hash[old__$short_setting]=$(sha256sum "${old[$short_setting]}" | cut -d' ' -f1)
if [ -z "${!short_setting}" ]
then
changed[$short_setting]=true
nothing_changed=false
fi
fi
if [ -f "${!short_setting}" ]
then
file_hash[new__$short_setting]=$(sha256sum "${!short_setting}" | cut -d' ' -f1)
if [[ "${file_hash[old__$short_setting]}" != "${file_hash[new__$short_setting]}" ]]
then
changed[$short_setting]=true
nothing_changed=false
fi
fi
else
if [[ "${!short_setting}" != "${old[$short_setting]}" ]]
then
changed[$short_setting]=true
nothing_changed=false
fi
fi
done
if [[ "$nothing_changed" == "true" ]]
then
ynh_print_info --message="Nothing has changed"
exit 0
fi
# Run validation if something is changed
ynh_script_progression --message="Validating the new configuration..." --weight=1
for short_setting in "${!old[@]}"
do
[[ "${changed[$short_setting]}" == "false" ]] && continue
local result=""
if type -t validate__$short_setting | grep -q '^function$' 2>/dev/null;
then
result="$(validate__$short_setting)"
fi
if [ -n "$result" ]
then
#
# Return a yaml such as:
#
# validation_errors:
# some_key: "An error message"
# some_other_key: "Another error message"
#
# We use changes_validated to know if this is
# the first validation error
if [[ "$changes_validated" == true ]]
then
ynh_return "validation_errors:"
fi
ynh_return " ${short_setting}: \"$result\""
changes_validated=false
fi
done
# If validation failed, exit the script right now (instead of going into apply)
# Yunohost core will pick up the errors returned via ynh_return previously
if [[ "$changes_validated" == "false" ]]
then
exit 0
fi
}
ynh_app_config_get() {
_ynh_app_config_get
}
ynh_app_config_show() {
_ynh_app_config_show
}
ynh_app_config_validate() {
_ynh_app_config_validate
}
ynh_app_config_apply() {
_ynh_app_config_apply
}
ynh_app_config_run() {
declare -Ag old=()
declare -Ag changed=()
declare -Ag file_hash=()
declare -Ag binds=()
declare -Ag types=()
declare -Ag formats=()
case $1 in
show)
ynh_app_config_get
ynh_app_config_show
;;
apply)
max_progression=4
ynh_script_progression --message="Reading config panel description and current configuration..."
ynh_app_config_get
ynh_app_config_validate
ynh_script_progression --message="Applying the new configuration..."
ynh_app_config_apply
ynh_script_progression --message="Configuration of $app completed" --last
;;
esac
}

View file

@ -43,12 +43,14 @@ ynh_replace_string () {
local target_file local target_file
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
set +o xtrace # set +x
local delimit=@ local delimit=@
# Escape the delimiter if it's in the string. # Escape the delimiter if it's in the string.
match_string=${match_string//${delimit}/"\\${delimit}"} match_string=${match_string//${delimit}/"\\${delimit}"}
replace_string=${replace_string//${delimit}/"\\${delimit}"} replace_string=${replace_string//${delimit}/"\\${delimit}"}
set -o xtrace # set -x
sed --in-place "s${delimit}${match_string}${delimit}${replace_string}${delimit}g" "$target_file" sed --in-place "s${delimit}${match_string}${delimit}${replace_string}${delimit}g" "$target_file"
} }

View file

@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
YNH_APP_BASEDIR=$(realpath $([[ "$(basename $0)" =~ ^backup|restore$ ]] && echo '../settings' || echo '..')) YNH_APP_BASEDIR=${YNH_APP_BASEDIR:-$(realpath ..)}
# Handle script crashes / failures # Handle script crashes / failures
# #
@ -473,6 +473,207 @@ ynh_replace_vars () {
done done
} }
# Get a value from heterogeneous file (yaml, json, php, python...)
#
# usage: ynh_read_var_in_file --file=PATH --key=KEY
# | arg: -f, --file= - the path to the file
# | arg: -k, --key= - the key to get
#
# This helpers match several var affectation use case in several languages
# We don't use jq or equivalent to keep comments and blank space in files
# This helpers work line by line, it is not able to work correctly
# if you have several identical keys in your files
#
# Example of line this helpers can managed correctly
# .yml
# title: YunoHost documentation
# email: 'yunohost@yunohost.org'
# .json
# "theme": "colib'ris",
# "port": 8102
# "some_boolean": false,
# "user": null
# .ini
# some_boolean = On
# action = "Clear"
# port = 20
# .php
# $user=
# user => 20
# .py
# USER = 8102
# user = 'https://donate.local'
# CUSTOM['user'] = 'YunoHost'
#
# Requires YunoHost version 4.3 or higher.
ynh_read_var_in_file() {
# Declare an array to define the options of this helper.
local legacy_args=fka
local -A args_array=( [f]=file= [k]=key= [a]=after=)
local file
local key
local after
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
after="${after:-}"
[[ -f $file ]] || ynh_die --message="File $file does not exists"
set +o xtrace # set +x
# Get the line number after which we search for the variable
local line_number=1
if [[ -n "$after" ]];
then
line_number=$(grep -n $after $file | cut -d: -f1)
if [[ -z "$line_number" ]];
then
set -o xtrace # set -x
return 1
fi
fi
local filename="$(basename -- "$file")"
local ext="${filename##*.}"
local endline=',;'
local assign="=>|:|="
local comments="#"
local string="\"'"
if [[ "$ext" =~ ^ini|env|toml|yml|yaml$ ]]; then
endline='#'
fi
if [[ "$ext" =~ ^ini|env$ ]]; then
comments="[;#]"
fi
if [[ "php" == "$ext" ]] || [[ "$ext" == "js" ]]; then
comments="//"
fi
local list='\[\s*['$string']?\w+['$string']?\]'
local var_part='^\s*((const|var|let)\s+)?\$?(\w+('$list')*(->|\.|\[))*\s*'
var_part+="[$string]?${key}[$string]?"
var_part+='\s*\]?\s*'
var_part+="($assign)"
var_part+='\s*'
# Extract the part after assignation sign
local expression_with_comment="$(tail +$line_number ${file} | grep -i -o -P $var_part'\K.*$' || echo YNH_NULL | head -n1)"
if [[ "$expression_with_comment" == "YNH_NULL" ]]; then
set -o xtrace # set -x
echo YNH_NULL
return 0
fi
# Remove comments if needed
local expression="$(echo "$expression_with_comment" | sed "s@$comments[^$string]*\$@@g" | sed "s@\s*[$endline]*\s*]*\$@@")"
local first_char="${expression:0:1}"
if [[ "$first_char" == '"' ]] ; then
echo "$expression" | grep -m1 -o -P '"\K([^"](\\")?)*[^\\](?=")' | head -n1 | sed 's/\\"/"/g'
elif [[ "$first_char" == "'" ]] ; then
echo "$expression" | grep -m1 -o -P "'\K([^'](\\\\')?)*[^\\\\](?=')" | head -n1 | sed "s/\\\\'/'/g"
else
echo "$expression"
fi
set -o xtrace # set -x
}
# Set a value into heterogeneous file (yaml, json, php, python...)
#
# usage: ynh_write_var_in_file --file=PATH --key=KEY --value=VALUE
# | arg: -f, --file= - the path to the file
# | arg: -k, --key= - the key to set
# | arg: -v, --value= - the value to set
#
# Requires YunoHost version 4.3 or higher.
ynh_write_var_in_file() {
# Declare an array to define the options of this helper.
local legacy_args=fkva
local -A args_array=( [f]=file= [k]=key= [v]=value= [a]=after=)
local file
local key
local value
local after
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
after="${after:-}"
[[ -f $file ]] || ynh_die --message="File $file does not exists"
set +o xtrace # set +x
# Get the line number after which we search for the variable
local line_number=1
if [[ -n "$after" ]];
then
line_number=$(grep -n $after $file | cut -d: -f1)
if [[ -z "$line_number" ]];
then
set -o xtrace # set -x
return 1
fi
fi
local range="${line_number},\$ "
local filename="$(basename -- "$file")"
local ext="${filename##*.}"
local endline=',;'
local assign="=>|:|="
local comments="#"
local string="\"'"
if [[ "$ext" =~ ^ini|env|toml|yml|yaml$ ]]; then
endline='#'
fi
if [[ "$ext" =~ ^ini|env$ ]]; then
comments="[;#]"
fi
if [[ "php" == "$ext" ]] || [[ "$ext" == "js" ]]; then
comments="//"
fi
local list='\[\s*['$string']?\w+['$string']?\]'
local var_part='^\s*((const|var|let)\s+)?\$?(\w+('$list')*(->|\.|\[))*\s*'
var_part+="[$string]?${key}[$string]?"
var_part+='\s*\]?\s*'
var_part+="($assign)"
var_part+='\s*'
# Extract the part after assignation sign
local expression_with_comment="$(tail +$line_number ${file} | grep -i -o -P $var_part'\K.*$' || echo YNH_NULL | head -n1)"
if [[ "$expression_with_comment" == "YNH_NULL" ]]; then
set -o xtrace # set -x
return 1
fi
# Remove comments if needed
local expression="$(echo "$expression_with_comment" | sed "s@$comments[^$string]*\$@@g" | sed "s@\s*[$endline]*\s*]*\$@@")"
endline=${expression_with_comment#"$expression"}
endline="$(echo "$endline" | sed 's/\\/\\\\/g')"
value="$(echo "$value" | sed 's/\\/\\\\/g')"
local first_char="${expression:0:1}"
delimiter=$'\001'
if [[ "$first_char" == '"' ]] ; then
# \ and sed is quite complex you need 2 \\ to get one in a sed
# So we need \\\\ to go through 2 sed
value="$(echo "$value" | sed 's/"/\\\\"/g')"
sed -ri "${range}s$delimiter"'(^'"${var_part}"'")([^"]|\\")*("[\s;,]*)(\s*'$comments'.*)?$'$delimiter'\1'"${value}"'"'"${endline}${delimiter}i" ${file}
elif [[ "$first_char" == "'" ]] ; then
# \ and sed is quite complex you need 2 \\ to get one in a sed
# However double quotes implies to double \\ to
# So we need \\\\\\\\ to go through 2 sed and 1 double quotes str
value="$(echo "$value" | sed "s/'/\\\\\\\\'/g")"
sed -ri "${range}s$delimiter(^${var_part}')([^']|\\')*('"'[\s,;]*)(\s*'$comments'.*)?$'$delimiter'\1'"${value}'${endline}${delimiter}i" ${file}
else
if [[ "$value" == *"'"* ]] || [[ "$value" == *'"'* ]] || [[ "$ext" =~ ^php|py|json|js$ ]] ; then
value='\"'"$(echo "$value" | sed 's/"/\\\\"/g')"'\"'
fi
if [[ "$ext" =~ ^yaml|yml$ ]] ; then
value=" $value"
fi
sed -ri "${range}s$delimiter(^${var_part}).*\$$delimiter\1${value}${endline}${delimiter}i" ${file}
fi
set -o xtrace # set -x
}
# Render templates with Jinja2 # Render templates with Jinja2
# #
# [internal] # [internal]
@ -516,6 +717,7 @@ ynh_secure_remove () {
local file local file
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
set +o xtrace # set +x
local forbidden_path=" \ local forbidden_path=" \
/var/www \ /var/www \
@ -543,6 +745,8 @@ ynh_secure_remove () {
else else
ynh_print_info --message="'$file' wasn't deleted because it doesn't exist." ynh_print_info --message="'$file' wasn't deleted because it doesn't exist."
fi fi
set -o xtrace # set -x
} }
# Read the value of a key in a ynh manifest file # Read the value of a key in a ynh manifest file

View file

@ -0,0 +1,17 @@
#!/bin/bash
# Exit hook on subcommand error or unset variable
set -eu
# Source YNH helpers
source /usr/share/yunohost/helpers
# Backup destination
backup_dir="${1}/data/multimedia"
if [ -e "/home/yunohost.multimedia/.nobackup" ]; then
exit 0
fi
# Backup multimedia directory
ynh_backup --src_path="/home/yunohost.multimedia" --dest_path="${backup_dir}" --is_big --not_mandatory

View file

@ -12,6 +12,7 @@ backup_dir="${1}/conf/ynh"
# Backup the configuration # Backup the configuration
ynh_backup "/etc/yunohost/firewall.yml" "${backup_dir}/firewall.yml" ynh_backup "/etc/yunohost/firewall.yml" "${backup_dir}/firewall.yml"
ynh_backup "/etc/yunohost/current_host" "${backup_dir}/current_host" ynh_backup "/etc/yunohost/current_host" "${backup_dir}/current_host"
ynh_backup "/etc/yunohost/domains" "${backup_dir}/domains"
[ ! -e "/etc/yunohost/settings.json" ] || ynh_backup "/etc/yunohost/settings.json" "${backup_dir}/settings.json" [ ! -e "/etc/yunohost/settings.json" ] || ynh_backup "/etc/yunohost/settings.json" "${backup_dir}/settings.json"
[ ! -d "/etc/yunohost/dyndns" ] || ynh_backup "/etc/yunohost/dyndns" "${backup_dir}/dyndns" [ ! -d "/etc/yunohost/dyndns" ] || ynh_backup "/etc/yunohost/dyndns" "${backup_dir}/dyndns"
[ ! -d "/etc/dkim" ] || ynh_backup "/etc/dkim" "${backup_dir}/dkim" [ ! -d "/etc/dkim" ] || ynh_backup "/etc/dkim" "${backup_dir}/dkim"

View file

@ -12,7 +12,7 @@ ynh_backup --src_path="./manually_modified_files_list"
for file in $(cat ./manually_modified_files_list) for file in $(cat ./manually_modified_files_list)
do do
ynh_backup --src_path="$file" [[ -e $file ]] && ynh_backup --src_path="$file"
done done
ynh_backup --src_path="/etc/ssowat/conf.json.persistent" ynh_backup --src_path="/etc/ssowat/conf.json.persistent"

View file

@ -35,6 +35,10 @@ do_init_regen() {
mkdir -p /home/yunohost.app mkdir -p /home/yunohost.app
chmod 755 /home/yunohost.app chmod 755 /home/yunohost.app
# Domain settings
mkdir -p /etc/yunohost/domains
chmod 700 /etc/yunohost/domains
# Backup folders # Backup folders
mkdir -p /home/yunohost.backup/archives mkdir -p /home/yunohost.backup/archives
chmod 750 /home/yunohost.backup/archives chmod 750 /home/yunohost.backup/archives
@ -51,6 +55,15 @@ do_init_regen() {
mkdir -p /var/cache/yunohost/repo mkdir -p /var/cache/yunohost/repo
chown root:root /var/cache/yunohost chown root:root /var/cache/yunohost
chmod 700 /var/cache/yunohost chmod 700 /var/cache/yunohost
cp yunoprompt.service /etc/systemd/system/yunoprompt.service
cp dpkg-origins /etc/dpkg/origins/yunohost
# Change dpkg vendor
# see https://wiki.debian.org/Derivatives/Guidelines#Vendor
readlink -f /etc/dpkg/origins/default | grep -q debian \
&& rm -f /etc/dpkg/origins/default \
&& ln -s /etc/dpkg/origins/yunohost /etc/dpkg/origins/default
} }
do_pre_regen() { do_pre_regen() {
@ -62,6 +75,7 @@ do_pre_regen() {
touch /etc/yunohost/services.yml touch /etc/yunohost/services.yml
yunohost tools shell -c "from yunohost.service import _get_services, _save_services; _save_services(_get_services())" yunohost tools shell -c "from yunohost.service import _get_services, _save_services; _save_services(_get_services())"
mkdir -p $pending_dir/etc/systemd/system
mkdir -p $pending_dir/etc/cron.d/ mkdir -p $pending_dir/etc/cron.d/
mkdir -p $pending_dir/etc/cron.daily/ mkdir -p $pending_dir/etc/cron.daily/
@ -82,7 +96,7 @@ EOF
# Cron job that renew lets encrypt certificates if there's any that needs renewal # Cron job that renew lets encrypt certificates if there's any that needs renewal
cat > $pending_dir/etc/cron.daily/yunohost-certificate-renew << EOF cat > $pending_dir/etc/cron.daily/yunohost-certificate-renew << EOF
#!/bin/bash #!/bin/bash
yunohost domain cert-renew --email yunohost domain cert renew --email
EOF EOF
# If we subscribed to a dyndns domain, add the corresponding cron # If we subscribed to a dyndns domain, add the corresponding cron
@ -122,8 +136,9 @@ HandleLidSwitch=ignore
HandleLidSwitchDocked=ignore HandleLidSwitchDocked=ignore
HandleLidSwitchExternalPower=ignore HandleLidSwitchExternalPower=ignore
EOF EOF
mkdir -p ${pending_dir}/etc/systemd/ cp yunoprompt.service ${pending_dir}/etc/systemd/system/yunoprompt.service
if [[ "$(yunohost settings get 'security.experimental.enabled')" == "True" ]] if [[ "$(yunohost settings get 'security.experimental.enabled')" == "True" ]]
then then
cp proc-hidepid.service ${pending_dir}/etc/systemd/system/proc-hidepid.service cp proc-hidepid.service ${pending_dir}/etc/systemd/system/proc-hidepid.service
@ -131,6 +146,8 @@ EOF
touch ${pending_dir}/etc/systemd/system/proc-hidepid.service touch ${pending_dir}/etc/systemd/system/proc-hidepid.service
fi fi
cp dpkg-origins ${pending_dir}/etc/dpkg/origins/yunohost
} }
do_post_regen() { do_post_regen() {
@ -174,6 +191,8 @@ do_post_regen() {
[ ! -e "/home/$USER" ] || setfacl -m g:all_users:--- /home/$USER [ ! -e "/home/$USER" ] || setfacl -m g:all_users:--- /home/$USER
done done
# Domain settings
mkdir -p /etc/yunohost/domains
# Misc configuration / state files # Misc configuration / state files
chown root:root $(ls /etc/yunohost/{*.yml,*.yaml,*.json,mysql,psql} 2>/dev/null) chown root:root $(ls /etc/yunohost/{*.yml,*.yaml,*.json,mysql,psql} 2>/dev/null)
@ -182,6 +201,7 @@ do_post_regen() {
# Apps folder, custom hooks folder # Apps folder, custom hooks folder
[[ ! -e /etc/yunohost/hooks.d ]] || (chown root /etc/yunohost/hooks.d && chmod 700 /etc/yunohost/hooks.d) [[ ! -e /etc/yunohost/hooks.d ]] || (chown root /etc/yunohost/hooks.d && chmod 700 /etc/yunohost/hooks.d)
[[ ! -e /etc/yunohost/apps ]] || (chown root /etc/yunohost/apps && chmod 700 /etc/yunohost/apps) [[ ! -e /etc/yunohost/apps ]] || (chown root /etc/yunohost/apps && chmod 700 /etc/yunohost/apps)
[[ ! -e /etc/yunohost/domains ]] || (chown root /etc/yunohost/domains && chmod 700 /etc/yunohost/domains)
# Create ssh.app and sftp.app groups if they don't exist yet # Create ssh.app and sftp.app groups if they don't exist yet
grep -q '^ssh.app:' /etc/group || groupadd ssh.app grep -q '^ssh.app:' /etc/group || groupadd ssh.app
@ -191,31 +211,24 @@ do_post_regen() {
[[ ! "$regen_conf_files" =~ "ntp.service.d/ynh-override.conf" ]] || { systemctl daemon-reload; systemctl restart ntp; } [[ ! "$regen_conf_files" =~ "ntp.service.d/ynh-override.conf" ]] || { systemctl daemon-reload; systemctl restart ntp; }
[[ ! "$regen_conf_files" =~ "nftables.service.d/ynh-override.conf" ]] || systemctl daemon-reload [[ ! "$regen_conf_files" =~ "nftables.service.d/ynh-override.conf" ]] || systemctl daemon-reload
[[ ! "$regen_conf_files" =~ "login.conf.d/ynh-override.conf" ]] || systemctl daemon-reload [[ ! "$regen_conf_files" =~ "login.conf.d/ynh-override.conf" ]] || systemctl daemon-reload
if [[ "$regen_conf_files" =~ "yunoprompt.service" ]]
then
systemctl daemon-reload
action=$([[ -e /etc/systemd/system/yunoprompt.service ]] && echo 'enable' || echo 'disable')
systemctl $action yunoprompt --quiet --now
fi
if [[ "$regen_conf_files" =~ "proc-hidepid.service" ]] if [[ "$regen_conf_files" =~ "proc-hidepid.service" ]]
then then
systemctl daemon-reload systemctl daemon-reload
action=$([[ -e /etc/systemd/system/proc-hidepid.service ]] && echo 'enable' || echo 'disable') action=$([[ -e /etc/systemd/system/proc-hidepid.service ]] && echo 'enable' || echo 'disable')
systemctl $action proc-hidepid --quiet --now systemctl $action proc-hidepid --quiet --now
fi fi
# Change dpkg vendor
# see https://wiki.debian.org/Derivatives/Guidelines#Vendor
readlink -f /etc/dpkg/origins/default | grep -q debian \
&& rm -f /etc/dpkg/origins/default \
&& ln -s /etc/dpkg/origins/yunohost /etc/dpkg/origins/default
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
init)
do_init_regen
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -48,8 +48,6 @@ regen_local_ca() {
popd popd
} }
do_init_regen() { do_init_regen() {
LOGFILE=/tmp/yunohost-ssl-init LOGFILE=/tmp/yunohost-ssl-init
@ -121,23 +119,4 @@ do_post_regen() {
fi fi
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
init)
do_init_regen
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -40,20 +40,4 @@ do_post_regen() {
systemctl restart ssh systemctl restart ssh
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -194,23 +194,4 @@ objectClass: top"
done done
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
init)
do_init_regen
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -22,23 +22,4 @@ do_post_regen() {
|| systemctl restart nslcd || systemctl restart nslcd
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
init)
do_init_regen
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -54,20 +54,4 @@ do_post_regen() {
update-alternatives --set php /usr/bin/php7.4 update-alternatives --set php /usr/bin/php7.4
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -70,20 +70,4 @@ do_post_regen() {
|| systemctl restart metronome || systemctl restart metronome
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -65,7 +65,7 @@ do_pre_regen() {
export experimental="$(yunohost settings get 'security.experimental.enabled')" export experimental="$(yunohost settings get 'security.experimental.enabled')"
ynh_render_template "security.conf.inc" "${nginx_conf_dir}/security.conf.inc" ynh_render_template "security.conf.inc" "${nginx_conf_dir}/security.conf.inc"
cert_status=$(yunohost domain cert-status --json) cert_status=$(yunohost domain cert status --json)
# add domain conf files # add domain conf files
for domain in $YNH_DOMAINS; do for domain in $YNH_DOMAINS; do
@ -135,23 +135,4 @@ do_post_regen() {
pgrep nginx && systemctl reload nginx || { journalctl --no-pager --lines=10 -u nginx >&2; exit 1; } pgrep nginx && systemctl reload nginx || { journalctl --no-pager --lines=10 -u nginx >&2; exit 1; }
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
init)
do_init_regen
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -80,20 +80,4 @@ do_post_regen() {
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -63,20 +63,4 @@ do_post_regen() {
systemctl restart dovecot systemctl restart dovecot
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -59,20 +59,4 @@ do_post_regen() {
systemctl -q restart rspamd.service systemctl -q restart rspamd.service
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -46,20 +46,4 @@ do_post_regen() {
|| systemctl restart mysql || systemctl restart mysql
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -10,20 +10,4 @@ do_post_regen() {
chown -R redis:adm /var/log/redis chown -R redis:adm /var/log/redis
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -61,23 +61,4 @@ do_post_regen() {
|| systemctl restart yunomdns || systemctl restart yunomdns
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
init)
do_init_regen
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -80,20 +80,4 @@ do_post_regen() {
systemctl restart dnsmasq systemctl restart dnsmasq
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -22,23 +22,4 @@ do_post_regen() {
|| systemctl restart unscd || systemctl restart unscd
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
init)
do_init_regen
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -27,20 +27,4 @@ do_post_regen() {
|| systemctl reload fail2ban || systemctl reload fail2ban
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -8,11 +8,11 @@ from publicsuffix2 import PublicSuffixList
from moulinette.utils.process import check_output from moulinette.utils.process import check_output
from yunohost.utils.network import dig from yunohost.utils.dns import dig, YNH_DYNDNS_DOMAINS
from yunohost.diagnosis import Diagnoser from yunohost.diagnosis import Diagnoser
from yunohost.domain import domain_list, _build_dns_conf, _get_maindomain from yunohost.domain import domain_list, _get_maindomain
from yunohost.dns import _build_dns_conf, _get_dns_zone_for_domain
YNH_DYNDNS_DOMAINS = ["nohost.me", "noho.st", "ynh.fr"]
SPECIAL_USE_TLDS = ["local", "localhost", "onion", "test"] SPECIAL_USE_TLDS = ["local", "localhost", "onion", "test"]
@ -26,17 +26,15 @@ class DNSRecordsDiagnoser(Diagnoser):
main_domain = _get_maindomain() main_domain = _get_maindomain()
all_domains = domain_list()["domains"] all_domains = domain_list(exclude_subdomains=True)["domains"]
for domain in all_domains: for domain in all_domains:
self.logger_debug("Diagnosing DNS conf for %s" % domain) self.logger_debug("Diagnosing DNS conf for %s" % domain)
is_subdomain = domain.split(".", 1)[1] in all_domains
is_specialusedomain = any( is_specialusedomain = any(
domain.endswith("." + tld) for tld in SPECIAL_USE_TLDS domain.endswith("." + tld) for tld in SPECIAL_USE_TLDS
) )
for report in self.check_domain( for report in self.check_domain(
domain, domain,
domain == main_domain, domain == main_domain,
is_subdomain=is_subdomain,
is_specialusedomain=is_specialusedomain, is_specialusedomain=is_specialusedomain,
): ):
yield report yield report
@ -55,16 +53,16 @@ class DNSRecordsDiagnoser(Diagnoser):
for report in self.check_expiration_date(domains_from_registrar): for report in self.check_expiration_date(domains_from_registrar):
yield report yield report
def check_domain(self, domain, is_main_domain, is_subdomain, is_specialusedomain): def check_domain(self, domain, is_main_domain, is_specialusedomain):
base_dns_zone = _get_dns_zone_for_domain(domain)
basename = domain.replace(base_dns_zone, "").rstrip(".") or "@"
expected_configuration = _build_dns_conf( expected_configuration = _build_dns_conf(
domain, include_empty_AAAA_if_no_ipv6=True domain, include_empty_AAAA_if_no_ipv6=True
) )
categories = ["basic", "mail", "xmpp", "extra"] categories = ["basic", "mail", "xmpp", "extra"]
# For subdomains, we only diagnosis A and AAAA records
if is_subdomain:
categories = ["basic"]
if is_specialusedomain: if is_specialusedomain:
categories = [] categories = []
@ -82,8 +80,20 @@ class DNSRecordsDiagnoser(Diagnoser):
results = {} results = {}
for r in records: for r in records:
id_ = r["type"] + ":" + r["name"] id_ = r["type"] + ":" + r["name"]
r["current"] = self.get_current_record(domain, r["name"], r["type"]) fqdn = r["name"] + "." + base_dns_zone if r["name"] != "@" else domain
# Ugly hack to not check mail records for subdomains stuff, otherwise will end up in a shitstorm of errors for people with many subdomains...
# Should find a cleaner solution in the suggested conf...
if r["type"] in ["MX", "TXT"] and fqdn not in [
domain,
f"mail._domainkey.{domain}",
f"_dmarc.{domain}",
]:
continue
r["current"] = self.get_current_record(fqdn, r["type"])
if r["value"] == "@": if r["value"] == "@":
r["value"] = domain + "." r["value"] = domain + "."
@ -106,7 +116,10 @@ class DNSRecordsDiagnoser(Diagnoser):
# A bad or missing A record is critical ... # A bad or missing A record is critical ...
# And so is a wrong AAAA record # And so is a wrong AAAA record
# (However, a missing AAAA record is acceptable) # (However, a missing AAAA record is acceptable)
if results["A:@"] != "OK" or results["AAAA:@"] == "WRONG": if (
results[f"A:{basename}"] != "OK"
or results[f"AAAA:{basename}"] == "WRONG"
):
return True return True
return False return False
@ -139,10 +152,9 @@ class DNSRecordsDiagnoser(Diagnoser):
yield output yield output
def get_current_record(self, domain, name, type_): def get_current_record(self, fqdn, type_):
query = "%s.%s" % (name, domain) if name != "@" else domain success, answers = dig(fqdn, type_, resolvers="force_external")
success, answers = dig(query, type_, resolvers="force_external")
if success != "ok": if success != "ok":
return None return None
@ -170,7 +182,7 @@ class DNSRecordsDiagnoser(Diagnoser):
) )
# For SPF, ignore parts starting by ip4: or ip6: # For SPF, ignore parts starting by ip4: or ip6:
if r["name"] == "@": if "v=spf1" in r["value"]:
current = { current = {
part part
for part in current for part in current
@ -189,7 +201,6 @@ class DNSRecordsDiagnoser(Diagnoser):
""" """
Alert if expiration date of a domain is soon Alert if expiration date of a domain is soon
""" """
details = {"not_found": [], "error": [], "warning": [], "success": []} details = {"not_found": [], "error": [], "warning": [], "success": []}
for domain in domains: for domain in domains:
@ -199,6 +210,7 @@ class DNSRecordsDiagnoser(Diagnoser):
status_ns, _ = dig(domain, "NS", resolvers="force_external") status_ns, _ = dig(domain, "NS", resolvers="force_external")
status_a, _ = dig(domain, "A", resolvers="force_external") status_a, _ = dig(domain, "A", resolvers="force_external")
if "ok" not in [status_ns, status_a]: if "ok" not in [status_ns, status_a]:
# i18n: diagnosis_domain_not_found_details
details["not_found"].append( details["not_found"].append(
( (
"diagnosis_domain_%s_details" % (expire_date), "diagnosis_domain_%s_details" % (expire_date),
@ -233,6 +245,12 @@ class DNSRecordsDiagnoser(Diagnoser):
# Allow to ignore specifically a single domain # Allow to ignore specifically a single domain
if len(details[alert_type]) == 1: if len(details[alert_type]) == 1:
meta["domain"] = details[alert_type][0][1]["domain"] meta["domain"] = details[alert_type][0][1]["domain"]
# i18n: diagnosis_domain_expiration_not_found
# i18n: diagnosis_domain_expiration_error
# i18n: diagnosis_domain_expiration_warning
# i18n: diagnosis_domain_expiration_success
# i18n: diagnosis_domain_expiration_not_found_details
yield dict( yield dict(
meta=meta, meta=meta,
data={}, data={},

View file

@ -121,6 +121,10 @@ class WebDiagnoser(Diagnoser):
for domain in domains: for domain in domains:
# i18n: diagnosis_http_bad_status_code
# i18n: diagnosis_http_connection_error
# i18n: diagnosis_http_timeout
# If both IPv4 and IPv6 (if applicable) are good # If both IPv4 and IPv6 (if applicable) are good
if all( if all(
results[ipversion][domain]["status"] == "ok" for ipversion in ipversions results[ipversion][domain]["status"] == "ok" for ipversion in ipversions

View file

@ -12,7 +12,7 @@ from moulinette.utils.filesystem import read_yaml
from yunohost.diagnosis import Diagnoser from yunohost.diagnosis import Diagnoser
from yunohost.domain import _get_maindomain, domain_list from yunohost.domain import _get_maindomain, domain_list
from yunohost.settings import settings_get from yunohost.settings import settings_get
from yunohost.utils.network import dig from yunohost.utils.dns import dig
DEFAULT_DNS_BLACKLIST = "/usr/share/yunohost/other/dnsbl_list.yml" DEFAULT_DNS_BLACKLIST = "/usr/share/yunohost/other/dnsbl_list.yml"
@ -35,11 +35,11 @@ class MailDiagnoser(Diagnoser):
# TODO check that the recent mail logs are not filled with thousand of email sending (unusual number of mail sent) # TODO check that the recent mail logs are not filled with thousand of email sending (unusual number of mail sent)
# TODO check for unusual failed sending attempt being refused in the logs ? # TODO check for unusual failed sending attempt being refused in the logs ?
checks = [ checks = [
"check_outgoing_port_25", "check_outgoing_port_25", # i18n: diagnosis_mail_outgoing_port_25_ok
"check_ehlo", "check_ehlo", # i18n: diagnosis_mail_ehlo_ok
"check_fcrdns", "check_fcrdns", # i18n: diagnosis_mail_fcrdns_ok
"check_blacklist", "check_blacklist", # i18n: diagnosis_mail_blacklist_ok
"check_queue", "check_queue", # i18n: diagnosis_mail_queue_ok
] ]
for check in checks: for check in checks:
self.logger_debug("Running " + check) self.logger_debug("Running " + check)
@ -102,6 +102,10 @@ class MailDiagnoser(Diagnoser):
continue continue
if r["status"] != "ok": if r["status"] != "ok":
# i18n: diagnosis_mail_ehlo_bad_answer
# i18n: diagnosis_mail_ehlo_bad_answer_details
# i18n: diagnosis_mail_ehlo_unreachable
# i18n: diagnosis_mail_ehlo_unreachable_details
summary = r["status"].replace("error_smtp_", "diagnosis_mail_ehlo_") summary = r["status"].replace("error_smtp_", "diagnosis_mail_ehlo_")
yield dict( yield dict(
meta={"test": "mail_ehlo", "ipversion": ipversion}, meta={"test": "mail_ehlo", "ipversion": ipversion},

View file

@ -76,7 +76,7 @@ class AppDiagnoser(Diagnoser):
for deprecated_helper in deprecated_helpers: for deprecated_helper in deprecated_helpers:
if ( if (
os.system( os.system(
f"grep -nr -q '{deprecated_helper}' {app['setting_path']}/scripts/" f"grep -hr '{deprecated_helper}' {app['setting_path']}/scripts/ | grep -v -q '^\s*#'"
) )
== 0 == 0
): ):

View file

@ -0,0 +1,9 @@
#!/bin/bash
# Exit hook on subcommand error or unset variable
set -eu
# Source YNH helpers
source /usr/share/yunohost/helpers
ynh_restore_file --origin_path="/home/yunohost.multimedia" --not_mandatory

View file

@ -2,6 +2,7 @@ backup_dir="$1/conf/ynh"
cp -a "${backup_dir}/current_host" /etc/yunohost/current_host cp -a "${backup_dir}/current_host" /etc/yunohost/current_host
cp -a "${backup_dir}/firewall.yml" /etc/yunohost/firewall.yml cp -a "${backup_dir}/firewall.yml" /etc/yunohost/firewall.yml
cp -a "${backup_dir}/domains" /etc/yunohost/domains
[ ! -e "${backup_dir}/settings.json" ] || cp -a "${backup_dir}/settings.json" "/etc/yunohost/settings.json" [ ! -e "${backup_dir}/settings.json" ] || cp -a "${backup_dir}/settings.json" "/etc/yunohost/settings.json"
[ ! -d "${backup_dir}/dyndns" ] || cp -raT "${backup_dir}/dyndns" "/etc/yunohost/dyndns" [ ! -d "${backup_dir}/dyndns" ] || cp -raT "${backup_dir}/dyndns" "/etc/yunohost/dyndns"
[ ! -d "${backup_dir}/dkim" ] || cp -raT "${backup_dir}/dkim" "/etc/dkim" [ ! -d "${backup_dir}/dkim" ] || cp -raT "${backup_dir}/dkim" "/etc/dkim"

View file

@ -0,0 +1,55 @@
version = "1.0"
i18n = "domain_config"
#
# Other things we may want to implement in the future:
#
# - maindomain handling
# - default app
# - autoredirect www in nginx conf
# - ?
#
[feature]
[feature.mail]
#services = ['postfix', 'dovecot']
[feature.mail.features_disclaimer]
type = "alert"
style = "warning"
icon = "warning"
[feature.mail.mail_out]
type = "boolean"
default = 1
[feature.mail.mail_in]
type = "boolean"
default = 1
#[feature.mail.backup_mx]
#type = "tags"
#default = []
#pattern.regexp = '^([^\W_A-Z]+([-]*[^\W_A-Z]+)*\.)+((xn--)?[^\W_]{2,})$'
#pattern.error = "pattern_error"
[feature.xmpp]
[feature.xmpp.xmpp]
type = "boolean"
default = 0
[dns]
[dns.registrar]
optional = true
# This part is automatically generated in DomainConfigPanel
# [dns.advanced]
#
# [dns.advanced.ttl]
# type = "number"
# min = 0
# default = 3600

View file

@ -0,0 +1,649 @@
[aliyun]
[aliyun.auth_key_id]
type = "string"
redact = true
[aliyun.auth_secret]
type = "string"
redact = true
[aurora]
[aurora.auth_api_key]
type = "string"
redact = true
[aurora.auth_secret_key]
type = "string"
redact = true
[azure]
[azure.auth_client_id]
type = "string"
redact = true
[azure.auth_client_secret]
type = "string"
redact = true
[azure.auth_tenant_id]
type = "string"
redact = true
[azure.auth_subscription_id]
type = "string"
redact = true
[azure.resource_group]
type = "string"
redact = true
[cloudflare]
[cloudflare.auth_username]
type = "string"
redact = true
[cloudflare.auth_token]
type = "string"
redact = true
[cloudflare.zone_id]
type = "string"
redact = true
[cloudns]
[cloudns.auth_id]
type = "string"
redact = true
[cloudns.auth_subid]
type = "string"
redact = true
[cloudns.auth_subuser]
type = "string"
redact = true
[cloudns.auth_password]
type = "password"
[cloudns.weight]
type = "number"
[cloudns.port]
type = "number"
[cloudxns]
[cloudxns.auth_username]
type = "string"
redact = true
[cloudxns.auth_token]
type = "string"
redact = true
[conoha]
[conoha.auth_region]
type = "string"
redact = true
[conoha.auth_token]
type = "string"
redact = true
[conoha.auth_username]
type = "string"
redact = true
[conoha.auth_password]
type = "password"
[conoha.auth_tenant_id]
type = "string"
redact = true
[constellix]
[constellix.auth_username]
type = "string"
redact = true
[constellix.auth_token]
type = "string"
redact = true
[digitalocean]
[digitalocean.auth_token]
type = "string"
redact = true
[dinahosting]
[dinahosting.auth_username]
type = "string"
redact = true
[dinahosting.auth_password]
type = "password"
[directadmin]
[directadmin.auth_password]
type = "password"
[directadmin.auth_username]
type = "string"
redact = true
[directadmin.endpoint]
type = "string"
redact = true
[dnsimple]
[dnsimple.auth_token]
type = "string"
redact = true
[dnsimple.auth_username]
type = "string"
redact = true
[dnsimple.auth_password]
type = "password"
[dnsimple.auth_2fa]
type = "string"
redact = true
[dnsmadeeasy]
[dnsmadeeasy.auth_username]
type = "string"
redact = true
[dnsmadeeasy.auth_token]
type = "string"
redact = true
[dnspark]
[dnspark.auth_username]
type = "string"
redact = true
[dnspark.auth_token]
type = "string"
redact = true
[dnspod]
[dnspod.auth_username]
type = "string"
redact = true
[dnspod.auth_token]
type = "string"
redact = true
[dreamhost]
[dreamhost.auth_token]
type = "string"
redact = true
[dynu]
[dynu.auth_token]
type = "string"
redact = true
[easydns]
[easydns.auth_username]
type = "string"
redact = true
[easydns.auth_token]
type = "string"
redact = true
[easyname]
[easyname.auth_username]
type = "string"
redact = true
[easyname.auth_password]
type = "password"
[euserv]
[euserv.auth_username]
type = "string"
redact = true
[euserv.auth_password]
type = "password"
[exoscale]
[exoscale.auth_key]
type = "string"
redact = true
[exoscale.auth_secret]
type = "string"
redact = true
[gandi]
[gandi.auth_token]
type = "string"
redact = true
[gandi.api_protocol]
type = "string"
choices.rpc = "RPC"
choices.rest = "REST"
default = "rest"
visible = "false"
[gehirn]
[gehirn.auth_token]
type = "string"
redact = true
[gehirn.auth_secret]
type = "string"
redact = true
[glesys]
[glesys.auth_username]
type = "string"
redact = true
[glesys.auth_token]
type = "string"
redact = true
[godaddy]
[godaddy.auth_key]
type = "string"
redact = true
[godaddy.auth_secret]
type = "string"
redact = true
[googleclouddns]
[goggleclouddns.auth_service_account_info]
type = "string"
redact = true
[gransy]
[gransy.auth_username]
type = "string"
redact = true
[gransy.auth_password]
type = "password"
[gratisdns]
[gratisdns.auth_username]
type = "string"
redact = true
[gratisdns.auth_password]
type = "password"
[henet]
[henet.auth_username]
type = "string"
redact = true
[henet.auth_password]
type = "password"
[hetzner]
[hetzner.auth_token]
type = "string"
redact = true
[hostingde]
[hostingde.auth_token]
type = "string"
redact = true
[hover]
[hover.auth_username]
type = "string"
redact = true
[hover.auth_password]
type = "password"
[infoblox]
[infoblox.auth_user]
type = "string"
redact = true
[infoblox.auth_psw]
type = "password"
[infoblox.ib_view]
type = "string"
redact = true
[infoblox.ib_host]
type = "string"
redact = true
[infomaniak]
[infomaniak.auth_token]
type = "string"
redact = true
[internetbs]
[internetbs.auth_key]
type = "string"
redact = true
[internetbs.auth_password]
type = "string"
redact = true
[inwx]
[inwx.auth_username]
type = "string"
redact = true
[inwx.auth_password]
type = "password"
[joker]
[joker.auth_token]
type = "string"
redact = true
[linode]
[linode.auth_token]
type = "string"
redact = true
[linode4]
[linode4.auth_token]
type = "string"
redact = true
[localzone]
[localzone.filename]
type = "string"
redact = true
[luadns]
[luadns.auth_username]
type = "string"
redact = true
[luadns.auth_token]
type = "string"
redact = true
[memset]
[memset.auth_token]
type = "string"
redact = true
[mythicbeasts]
[mythicbeasts.auth_username]
type = "string"
redact = true
[mythicbeasts.auth_password]
type = "password"
[mythicbeasts.auth_token]
type = "string"
redact = true
[namecheap]
[namecheap.auth_token]
type = "string"
redact = true
[namecheap.auth_username]
type = "string"
redact = true
[namecheap.auth_client_ip]
type = "string"
redact = true
[namecheap.auth_sandbox]
type = "string"
redact = true
[namesilo]
[namesilo.auth_token]
type = "string"
redact = true
[netcup]
[netcup.auth_customer_id]
type = "string"
redact = true
[netcup.auth_api_key]
type = "string"
redact = true
[netcup.auth_api_password]
type = "string"
redact = true
[nfsn]
[nfsn.auth_username]
type = "string"
redact = true
[nfsn.auth_token]
type = "string"
redact = true
[njalla]
[njalla.auth_token]
type = "string"
redact = true
[nsone]
[nsone.auth_token]
type = "string"
redact = true
[onapp]
[onapp.auth_username]
type = "string"
redact = true
[onapp.auth_token]
type = "string"
redact = true
[onapp.auth_server]
type = "string"
redact = true
[online]
[online.auth_token]
type = "string"
redact = true
[ovh]
[ovh.auth_entrypoint]
type = "select"
choices = ["ovh-eu", "ovh-ca", "soyoustart-eu", "soyoustart-ca", "kimsufi-eu", "kimsufi-ca"]
default = "ovh-eu"
[ovh.auth_application_key]
type = "string"
redact = true
[ovh.auth_application_secret]
type = "string"
redact = true
[ovh.auth_consumer_key]
type = "string"
redact = true
[plesk]
[plesk.auth_username]
type = "string"
redact = true
[plesk.auth_password]
type = "password"
[plesk.plesk_server]
type = "string"
redact = true
[pointhq]
[pointhq.auth_username]
type = "string"
redact = true
[pointhq.auth_token]
type = "string"
redact = true
[powerdns]
[powerdns.auth_token]
type = "string"
redact = true
[powerdns.pdns_server]
type = "string"
redact = true
[powerdns.pdns_server_id]
type = "string"
redact = true
[powerdns.pdns_disable_notify]
type = "boolean"
[rackspace]
[rackspace.auth_account]
type = "string"
redact = true
[rackspace.auth_username]
type = "string"
redact = true
[rackspace.auth_api_key]
type = "string"
redact = true
[rackspace.auth_token]
type = "string"
redact = true
[rackspace.sleep_time]
type = "string"
redact = true
[rage4]
[rage4.auth_username]
type = "string"
redact = true
[rage4.auth_token]
type = "string"
redact = true
[rcodezero]
[rcodezero.auth_token]
type = "string"
redact = true
[route53]
[route53.auth_access_key]
type = "string"
redact = true
[route53.auth_access_secret]
type = "string"
redact = true
[route53.private_zone]
type = "string"
redact = true
[route53.auth_username]
type = "string"
redact = true
[route53.auth_token]
type = "string"
redact = true
[safedns]
[safedns.auth_token]
type = "string"
redact = true
[sakuracloud]
[sakuracloud.auth_token]
type = "string"
redact = true
[sakuracloud.auth_secret]
type = "string"
redact = true
[softlayer]
[softlayer.auth_username]
type = "string"
redact = true
[softlayer.auth_api_key]
type = "string"
redact = true
[transip]
[transip.auth_username]
type = "string"
redact = true
[transip.auth_api_key]
type = "string"
redact = true
[ultradns]
[ultradns.auth_token]
type = "string"
redact = true
[ultradns.auth_username]
type = "string"
redact = true
[ultradns.auth_password]
type = "password"
[vultr]
[vultr.auth_token]
type = "string"
redact = true
[yandex]
[yandex.auth_token]
type = "string"
redact = true
[zeit]
[zeit.auth_token]
type = "string"
redact = true
[zilore]
[zilore.auth_key]
type = "string"
redact = true
[zonomi]
[zonomy.auth_token]
type = "string"
redact = true
[zonomy.auth_entrypoint]
type = "string"
redact = true

View file

@ -30,7 +30,7 @@ skip-external-locking
key_buffer_size = 16K key_buffer_size = 16K
max_allowed_packet = 16M max_allowed_packet = 16M
table_open_cache = 4 table_open_cache = 4
sort_buffer_size = 256K sort_buffer_size = 4M
read_buffer_size = 256K read_buffer_size = 256K
read_rnd_buffer_size = 256K read_rnd_buffer_size = 256K
net_buffer_length = 2K net_buffer_length = 2K

35
debian/changelog vendored
View file

@ -4,6 +4,41 @@ yunohost (11.0.0~alpha) unstable; urgency=low
-- Alexandre Aubin <alex.aubin@mailoo.org> Fri, 05 Feb 2021 00:02:38 +0100 -- Alexandre Aubin <alex.aubin@mailoo.org> Fri, 05 Feb 2021 00:02:38 +0100
yunohost (4.3.0) testing; urgency=low
- [users] Import/export users from/to CSV ([#1089](https://github.com/YunoHost/yunohost/pull/1089))
- [domain] Add mDNS for .local domains / replace avahi-daemon ([#1112](https://github.com/YunoHost/yunohost/pull/1112))
- [settings] new setting to enable experimental security features ([#1290](https://github.com/YunoHost/yunohost/pull/1290))
- [settings] new setting to handle https redirect ([#1304](https://github.com/YunoHost/yunohost/pull/1304))
- [diagnosis] add an "app" section to check that app are in catalog with good quality, check for deprecated practices ([#1217](https://github.com/YunoHost/yunohost/pull/1217))
- [diagnosis] report suspiciously high number of auth failures ([#1292](https://github.com/YunoHost/yunohost/pull/1292))
- [refactor] Rework the authentication system ([#1183](https://github.com/YunoHost/yunohost/pull/1183))
- [enh] New config-panel mechanism ([#987](https://github.com/YunoHost/yunohost/pull/987))
- [enh] Add backup for multimedia files (88063dc7)
- [enh] Configure automatically the DNS records using lexicon ([#1315](https://github.com/YunoHost/yunohost/pull/1315))
- also brings domain settings, domain config panel, subdomain awareness, improvements in dns recommended conf
- [i18n] Translations updated for Catalan, Chinese (Simplified), Czech, Esperanto, French, Galician, German, Italian, Occitan, Persian, Portuguese, Spanish, Ukrainian
Thanks to all contributors <3 ! (Corentin Mercier, Daniel, Éric Gaspar, Flavio Cristoforetti, Gregor Lenz, José M, Kay0u, ljf, MercierCorentin, mifegui, Paco, Parviz Homayun, ppr, tituspijean, Tymofii-Lytvynenko)
-- Alexandre Aubin <alex.aubin@mailoo.org> Sun, 19 Sep 2021 23:55:21 +0200
yunohost (4.2.8.3) stable; urgency=low
- [fix] mysql: Another bump for sort_buffer_size to make Nextcloud 22 work (34e9246b)
Thanks to all contributors <3 ! (ljf (zamentur))
-- Kay0u <pierre@kayou.io> Fri, 10 Sep 2021 10:40:38 +0200
yunohost (4.2.8.2) stable; urgency=low
- [fix] mysql: Bump sort_buffer_size to 256K to fix Nextcloud 22 installation (d8c49619)
Thanks to all contributors <3 ! (ericg)
-- Alexandre Aubin <alex.aubin@mailoo.org> Tue, 07 Sep 2021 23:23:18 +0200
yunohost (4.2.8.1) stable; urgency=low yunohost (4.2.8.1) stable; urgency=low
- [fix] Safer location for slapd backup during hdb/mdb migration (3c646b3d) - [fix] Safer location for slapd backup during hdb/mdb migration (3c646b3d)

2
debian/control vendored
View file

@ -14,7 +14,7 @@ Depends: ${python3:Depends}, ${misc:Depends}
, python3-psutil, python3-requests, python3-dnspython, python3-openssl , python3-psutil, python3-requests, python3-dnspython, python3-openssl
, python3-miniupnpc, python3-dbus, python3-jinja2 , python3-miniupnpc, python3-dbus, python3-jinja2
, python3-toml, python3-packaging, python3-publicsuffix2 , python3-toml, python3-packaging, python3-publicsuffix2
, python3-ldap, python3-zeroconf , python3-ldap, python3-zeroconf, python3-lexicon,
, python-is-python3 , python-is-python3
, nginx, nginx-extras (>=1.18) , nginx, nginx-extras (>=1.18)
, apt, apt-transport-https, apt-utils, dirmngr , apt, apt-transport-https, apt-utils, dirmngr

13
debian/install vendored
View file

@ -1,17 +1,8 @@
bin/* /usr/bin/ bin/* /usr/bin/
sbin/* /usr/sbin/
data/* /usr/share/yunohost/
data/bash-completion.d/yunohost /etc/bash_completion.d/ data/bash-completion.d/yunohost /etc/bash_completion.d/
doc/yunohost.8.gz /usr/share/man/man8/ doc/yunohost.8.gz /usr/share/man/man8/
data/actionsmap/* /usr/share/moulinette/actionsmap/
data/hooks/* /usr/share/yunohost/hooks/
data/other/yunoprompt.service /etc/systemd/system/
data/other/password/* /usr/share/yunohost/other/password/
data/other/dpkg-origins/yunohost /etc/dpkg/origins
data/other/dnsbl_list.yml /usr/share/yunohost/other/
data/other/ffdhe2048.pem /usr/share/yunohost/other/
data/other/* /usr/share/yunohost/yunohost-config/moulinette/
data/templates/* /usr/share/yunohost/templates/
data/helpers /usr/share/yunohost/
data/helpers.d/* /usr/share/yunohost/helpers.d/
lib/metronome/modules/* /usr/lib/metronome/modules/ lib/metronome/modules/* /usr/lib/metronome/modules/
locales/* /usr/lib/moulinette/yunohost/locales/ locales/* /usr/lib/moulinette/yunohost/locales/
src/yunohost /usr/lib/moulinette src/yunohost /usr/lib/moulinette

11
debian/postinst vendored
View file

@ -5,6 +5,9 @@ set -e
do_configure() { do_configure() {
rm -rf /var/cache/moulinette/* rm -rf /var/cache/moulinette/*
mkdir -p /usr/share/moulinette/actionsmap/
ln -sf /usr/share/yunohost/actionsmap/yunohost.yml /usr/share/moulinette/actionsmap/yunohost.yml
if [ ! -f /etc/yunohost/installed ]; then if [ ! -f /etc/yunohost/installed ]; then
# If apps/ is not empty, we're probably already installed in the past and # If apps/ is not empty, we're probably already installed in the past and
# something funky happened ... # something funky happened ...
@ -31,14 +34,6 @@ do_configure() {
yunohost diagnosis run --force yunohost diagnosis run --force
fi fi
# Change dpkg vendor
# see https://wiki.debian.org/Derivatives/Guidelines#Vendor
readlink -f /etc/dpkg/origins/default | grep -q debian \
&& rm -f /etc/dpkg/origins/default \
&& ln -s /etc/dpkg/origins/yunohost /etc/dpkg/origins/default
# Yunoprompt
systemctl enable yunoprompt.service
} }
# summary of how this script can be called: # summary of how this script can be called:

View file

@ -10,11 +10,10 @@ routes:
Doc auto-generated by [this script](https://github.com/YunoHost/yunohost/blob/{{ current_commit }}/doc/generate_helper_doc.py) on {{data.date}} (YunoHost version {{data.version}}) Doc auto-generated by [this script](https://github.com/YunoHost/yunohost/blob/{{ current_commit }}/doc/generate_helper_doc.py) on {{data.date}} (YunoHost version {{data.version}})
{% for category, helpers in data.helpers %} {% for category, helpers in data.helpers %}
### {{ category.upper() }} ## {{ category.upper() }}
{% for h in helpers %} {% for h in helpers %}
**{{ h.name }}**<br/> #### {{ h.name }}
[details summary="<i>{{ h.brief }}</i>" class="helper-card-subtitle text-muted"] [details summary="<i>{{ h.brief }}</i>" class="helper-card-subtitle text-muted"]
<p></p>
**Usage**: `{{ h.usage }}` **Usage**: `{{ h.usage }}`
{%- if h.args %} {%- if h.args %}

View file

@ -6,7 +6,6 @@
"app_already_installed": "{app} تم تنصيبه مِن قبل", "app_already_installed": "{app} تم تنصيبه مِن قبل",
"app_already_up_to_date": "{app} تم تحديثه مِن قَبل", "app_already_up_to_date": "{app} تم تحديثه مِن قَبل",
"app_argument_required": "المُعامِل '{name}' مطلوب", "app_argument_required": "المُعامِل '{name}' مطلوب",
"app_change_url_failed_nginx_reload": "فشلت عملية إعادة تشغيل NGINX. ها هي نتيجة الأمر 'nginx -t':\n{nginx_errors}",
"app_extraction_failed": "تعذر فك الضغط عن ملفات التنصيب", "app_extraction_failed": "تعذر فك الضغط عن ملفات التنصيب",
"app_install_files_invalid": "ملفات التنصيب خاطئة", "app_install_files_invalid": "ملفات التنصيب خاطئة",
"app_not_correctly_installed": "يبدو أن التطبيق {app} لم يتم تنصيبه بشكل صحيح", "app_not_correctly_installed": "يبدو أن التطبيق {app} لم يتم تنصيبه بشكل صحيح",
@ -40,7 +39,6 @@
"domain_creation_failed": "تعذرت عملية إنشاء النطاق", "domain_creation_failed": "تعذرت عملية إنشاء النطاق",
"domain_deleted": "تم حذف النطاق", "domain_deleted": "تم حذف النطاق",
"domain_exists": "اسم النطاق موجود مِن قبل", "domain_exists": "اسم النطاق موجود مِن قبل",
"domain_unknown": "النطاق مجهول",
"domains_available": "النطاقات المتوفرة :", "domains_available": "النطاقات المتوفرة :",
"done": "تم", "done": "تم",
"downloading": "عملية التنزيل جارية …", "downloading": "عملية التنزيل جارية …",
@ -55,7 +53,6 @@
"pattern_domain": "يتوجب أن يكون إسم نطاق صالح (مثل my-domain.org)", "pattern_domain": "يتوجب أن يكون إسم نطاق صالح (مثل my-domain.org)",
"pattern_email": "يتوجب أن يكون عنوان بريد إلكتروني صالح (مثل someone@domain.org)", "pattern_email": "يتوجب أن يكون عنوان بريد إلكتروني صالح (مثل someone@domain.org)",
"pattern_password": "يتوجب أن تكون مكونة من 3 حروف على الأقل", "pattern_password": "يتوجب أن تكون مكونة من 3 حروف على الأقل",
"pattern_positive_number": "يجب أن يكون عددا إيجابيا",
"restore_extracting": "جارٍ فك الضغط عن الملفات التي نحتاجها من النسخة الاحتياطية…", "restore_extracting": "جارٍ فك الضغط عن الملفات التي نحتاجها من النسخة الاحتياطية…",
"server_shutdown": "سوف ينطفئ الخادوم", "server_shutdown": "سوف ينطفئ الخادوم",
"server_shutdown_confirm": "سوف ينطفئ الخادوم حالا. متأكد ؟ [{answers}]", "server_shutdown_confirm": "سوف ينطفئ الخادوم حالا. متأكد ؟ [{answers}]",

View file

@ -6,10 +6,9 @@
"app_already_installed": "{app} ja està instal·lada", "app_already_installed": "{app} ja està instal·lada",
"app_already_installed_cant_change_url": "Aquesta aplicació ja està instal·lada. La URL no és pot canviar únicament amb aquesta funció. Mireu a `app changeurl` si està disponible.", "app_already_installed_cant_change_url": "Aquesta aplicació ja està instal·lada. La URL no és pot canviar únicament amb aquesta funció. Mireu a `app changeurl` si està disponible.",
"app_already_up_to_date": "{app} ja està actualitzada", "app_already_up_to_date": "{app} ja està actualitzada",
"app_argument_choice_invalid": "Utilitzeu una de les opcions «{choices}» per l'argument «{name}»", "app_argument_choice_invalid": "Utilitzeu una de les opcions «{choices}» per l'argument «{name}» en lloc de «{value}»",
"app_argument_invalid": "Escolliu un valor vàlid per l'argument «{name}»: {error}", "app_argument_invalid": "Escolliu un valor vàlid per l'argument «{name}»: {error}",
"app_argument_required": "Es necessita l'argument '{name}'", "app_argument_required": "Es necessita l'argument '{name}'",
"app_change_url_failed_nginx_reload": "No s'ha pogut tornar a carregar NGINX. Aquí teniu el resultat de \"nginx -t\":\n{nginx_errors}",
"app_change_url_identical_domains": "L'antic i el nou domini/camí són idèntics ('{domain}{path}'), no hi ha res per fer.", "app_change_url_identical_domains": "L'antic i el nou domini/camí són idèntics ('{domain}{path}'), no hi ha res per fer.",
"app_change_url_no_script": "L'aplicació '{app_name}' encara no permet modificar la URL. Potser s'ha d'actualitzar.", "app_change_url_no_script": "L'aplicació '{app_name}' encara no permet modificar la URL. Potser s'ha d'actualitzar.",
"app_change_url_success": "La URL de {app} ara és {domain}{path}", "app_change_url_success": "La URL de {app} ara és {domain}{path}",
@ -112,11 +111,11 @@
"certmanager_self_ca_conf_file_not_found": "No s'ha trobat el fitxer de configuració per l'autoritat del certificat auto-signat (fitxer: {file})", "certmanager_self_ca_conf_file_not_found": "No s'ha trobat el fitxer de configuració per l'autoritat del certificat auto-signat (fitxer: {file})",
"certmanager_unable_to_parse_self_CA_name": "No s'ha pogut analitzar el nom de l'autoritat del certificat auto-signat (fitxer: {file})", "certmanager_unable_to_parse_self_CA_name": "No s'ha pogut analitzar el nom de l'autoritat del certificat auto-signat (fitxer: {file})",
"confirm_app_install_warning": "Atenció: Aquesta aplicació funciona, però no està ben integrada amb YunoHost. Algunes característiques com la autenticació única i la còpia de seguretat/restauració poden no estar disponibles. Voleu instal·lar-la de totes maneres? [{answers}] ", "confirm_app_install_warning": "Atenció: Aquesta aplicació funciona, però no està ben integrada amb YunoHost. Algunes característiques com la autenticació única i la còpia de seguretat/restauració poden no estar disponibles. Voleu instal·lar-la de totes maneres? [{answers}] ",
"confirm_app_install_danger": "PERILL! Aquesta aplicació encara és experimental (si no és que no funciona directament)! No hauríeu d'instal·lar-la a no ser que sapigueu el que feu. No obtindreu CAP AJUDA si l'aplicació no funciona o trenca el sistema Si accepteu el risc, escriviu «{answers}»", "confirm_app_install_danger": "PERILL! Aquesta aplicació encara és experimental (si no és que no funciona directament)! No hauríeu d'instal·lar-la a no ser que sapigueu el que feu. No obtindreu CAP AJUDA si l'aplicació no funciona o trenca el sistema... Si accepteu el risc, escriviu «{answers}»",
"confirm_app_install_thirdparty": "PERILL! Aquesta aplicació no es part del catàleg d'aplicacions de YunoHost. La instal·lació d'aplicacions de terceres parts pot comprometre la integritat i seguretat del seu sistema. No hauríeu d'instal·lar-ne a no ser que sapigueu el que feu. No obtindreu CAP AJUDA si l'aplicació no funciona o trenca el sistema… Si accepteu el risc, escriviu «{answers}»", "confirm_app_install_thirdparty": "PERILL! Aquesta aplicació no es part del catàleg d'aplicacions de YunoHost. La instal·lació d'aplicacions de terceres parts pot comprometre la integritat i seguretat del seu sistema. No hauríeu d'instal·lar-ne a no ser que sapigueu el que feu. No obtindreu CAP AJUDA si l'aplicació no funciona o trenca el sistema… Si accepteu el risc, escriviu «{answers}»",
"custom_app_url_required": "Heu de especificar una URL per actualitzar la vostra aplicació personalitzada {app}", "custom_app_url_required": "Heu de especificar una URL per actualitzar la vostra aplicació personalitzada {app}",
"admin_password_too_long": "Trieu una contrasenya de menys de 127 caràcters", "admin_password_too_long": "Trieu una contrasenya de menys de 127 caràcters",
"dpkg_is_broken": "No es pot fer això en aquest instant perquè dpkg/APT (els gestors de paquets del sistema) sembla estar mal configurat Podeu intentar solucionar-ho connectant-vos per SSH i executant «sudo apt install --fix-broken» i/o «sudo dpkg --configure -a».", "dpkg_is_broken": "No es pot fer això en aquest instant perquè dpkg/APT (els gestors de paquets del sistema) sembla estar mal configurat... Podeu intentar solucionar-ho connectant-vos per SSH i executant «sudo apt install --fix-broken» i/o «sudo dpkg --configure -a».",
"domain_cannot_remove_main": "No es pot eliminar «{domain}» ja que és el domini principal, primer s'ha d'establir un nou domini principal utilitzant «yunohost domain main-domain -n <un-altre-domini>»; aquí hi ha una llista dels possibles dominis: {other_domains}", "domain_cannot_remove_main": "No es pot eliminar «{domain}» ja que és el domini principal, primer s'ha d'establir un nou domini principal utilitzant «yunohost domain main-domain -n <un-altre-domini>»; aquí hi ha una llista dels possibles dominis: {other_domains}",
"domain_cert_gen_failed": "No s'ha pogut generar el certificat", "domain_cert_gen_failed": "No s'ha pogut generar el certificat",
"domain_created": "S'ha creat el domini", "domain_created": "S'ha creat el domini",
@ -130,10 +129,9 @@
"domain_dyndns_root_unknown": "Domini DynDNS principal desconegut", "domain_dyndns_root_unknown": "Domini DynDNS principal desconegut",
"domain_hostname_failed": "No s'ha pogut establir un nou nom d'amfitrió. Això podria causar problemes més tard (podria no passar res).", "domain_hostname_failed": "No s'ha pogut establir un nou nom d'amfitrió. Això podria causar problemes més tard (podria no passar res).",
"domain_uninstall_app_first": "Aquestes aplicacions encara estan instal·lades en el vostre domini:\n{apps}\n\nDesinstal·leu-les utilitzant l'ordre «yunohost app remove id_de_lapplicació» o moveu-les a un altre domini amb «yunohost app change-url id_de_lapplicació» abans d'eliminar el domini", "domain_uninstall_app_first": "Aquestes aplicacions encara estan instal·lades en el vostre domini:\n{apps}\n\nDesinstal·leu-les utilitzant l'ordre «yunohost app remove id_de_lapplicació» o moveu-les a un altre domini amb «yunohost app change-url id_de_lapplicació» abans d'eliminar el domini",
"domain_unknown": "Domini desconegut",
"domains_available": "Dominis disponibles:", "domains_available": "Dominis disponibles:",
"done": "Fet", "done": "Fet",
"downloading": "Descarregant", "downloading": "Descarregant...",
"dyndns_could_not_check_provide": "No s'ha pogut verificar si {provider} pot oferir {domain}.", "dyndns_could_not_check_provide": "No s'ha pogut verificar si {provider} pot oferir {domain}.",
"dyndns_could_not_check_available": "No s'ha pogut verificar la disponibilitat de {domain} a {provider}.", "dyndns_could_not_check_available": "No s'ha pogut verificar la disponibilitat de {domain} a {provider}.",
"dyndns_ip_update_failed": "No s'ha pogut actualitzar l'adreça IP al DynDNS", "dyndns_ip_update_failed": "No s'ha pogut actualitzar l'adreça IP al DynDNS",
@ -177,7 +175,7 @@
"iptables_unavailable": "No podeu modificar les iptables aquí. O bé sou en un contenidor o bé el vostre nucli no és compatible amb aquesta opció", "iptables_unavailable": "No podeu modificar les iptables aquí. O bé sou en un contenidor o bé el vostre nucli no és compatible amb aquesta opció",
"log_corrupted_md_file": "El fitxer de metadades YAML associat amb els registres està malmès: « {md_file} »\nError: {error}", "log_corrupted_md_file": "El fitxer de metadades YAML associat amb els registres està malmès: « {md_file} »\nError: {error}",
"log_link_to_log": "El registre complet d'aquesta operació: «<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>»", "log_link_to_log": "El registre complet d'aquesta operació: «<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>»",
"log_help_to_get_log": "Per veure el registre de l'operació « {desc} », utilitzeu l'ordre «yunohost log show {name}{name} »", "log_help_to_get_log": "Per veure el registre de l'operació « {desc} », utilitzeu l'ordre «yunohost log show {name} »",
"log_link_to_failed_log": "No s'ha pogut completar l'operació « {desc} ». Per obtenir ajuda, <a href=\"#/tools/logs/{name}\">proveïu el registre complete de l'operació clicant aquí</a>", "log_link_to_failed_log": "No s'ha pogut completar l'operació « {desc} ». Per obtenir ajuda, <a href=\"#/tools/logs/{name}\">proveïu el registre complete de l'operació clicant aquí</a>",
"log_help_to_get_failed_log": "No s'ha pogut completar l'operació « {desc} ». Per obtenir ajuda, compartiu el registre complete de l'operació utilitzant l'ordre «yunohost log share {name} »", "log_help_to_get_failed_log": "No s'ha pogut completar l'operació « {desc} ». Per obtenir ajuda, compartiu el registre complete de l'operació utilitzant l'ordre «yunohost log share {name} »",
"log_does_exists": "No hi ha cap registre per l'operació amb el nom«{log} », utilitzeu «yunohost log list» per veure tots els registre d'operació disponibles", "log_does_exists": "No hi ha cap registre per l'operació amb el nom«{log} », utilitzeu «yunohost log list» per veure tots els registre d'operació disponibles",
@ -237,7 +235,6 @@
"pattern_mailbox_quota": "Ha de ser una mida amb el sufix b/k/M/G/T o 0 per no tenir quota", "pattern_mailbox_quota": "Ha de ser una mida amb el sufix b/k/M/G/T o 0 per no tenir quota",
"pattern_password": "Ha de tenir un mínim de 3 caràcters", "pattern_password": "Ha de tenir un mínim de 3 caràcters",
"pattern_port_or_range": "Ha de ser un número de port vàlid (i.e. 0-65535) o un interval de ports (ex. 100:200)", "pattern_port_or_range": "Ha de ser un número de port vàlid (i.e. 0-65535) o un interval de ports (ex. 100:200)",
"pattern_positive_number": "Ha de ser un nombre positiu",
"pattern_username": "Ha d'estar compost per caràcters alfanumèrics en minúscula i guió baix exclusivament", "pattern_username": "Ha d'estar compost per caràcters alfanumèrics en minúscula i guió baix exclusivament",
"pattern_password_app": "Les contrasenyes no poden de tenir els següents caràcters: {forbidden_chars}", "pattern_password_app": "Les contrasenyes no poden de tenir els següents caràcters: {forbidden_chars}",
"port_already_closed": "El port {port} ja està tancat per les connexions {ip_version}", "port_already_closed": "El port {port} ja està tancat per les connexions {ip_version}",
@ -254,7 +251,7 @@
"regenconf_up_to_date": "La configuració ja està al dia per la categoria «{category}»", "regenconf_up_to_date": "La configuració ja està al dia per la categoria «{category}»",
"regenconf_updated": "S'ha actualitzat la configuració per la categoria «{category}»", "regenconf_updated": "S'ha actualitzat la configuració per la categoria «{category}»",
"regenconf_would_be_updated": "La configuració hagués estat actualitzada per la categoria «{category}»", "regenconf_would_be_updated": "La configuració hagués estat actualitzada per la categoria «{category}»",
"regenconf_dry_pending_applying": "Verificació de la configuració pendent que s'hauria d'haver aplicat per la categoria «{category}»", "regenconf_dry_pending_applying": "Verificació de la configuració pendent que s'hauria d'haver aplicat per la categoria «{category}»...",
"regenconf_failed": "No s'ha pogut regenerar la configuració per la/les categoria/es : {categories}", "regenconf_failed": "No s'ha pogut regenerar la configuració per la/les categoria/es : {categories}",
"regenconf_pending_applying": "Aplicació de la configuració pendent per la categoria «{category}»...", "regenconf_pending_applying": "Aplicació de la configuració pendent per la categoria «{category}»...",
"restore_already_installed_app": "Una aplicació amb la ID «{app}» ja està instal·lada", "restore_already_installed_app": "Una aplicació amb la ID «{app}» ja està instal·lada",
@ -262,15 +259,15 @@
"restore_cleaning_failed": "No s'ha pogut netejar el directori temporal de restauració", "restore_cleaning_failed": "No s'ha pogut netejar el directori temporal de restauració",
"restore_complete": "Restauració completada", "restore_complete": "Restauració completada",
"restore_confirm_yunohost_installed": "Esteu segur de voler restaurar un sistema ja instal·lat? [{answers}]", "restore_confirm_yunohost_installed": "Esteu segur de voler restaurar un sistema ja instal·lat? [{answers}]",
"restore_extracting": "Extracció dels fitxers necessaris de l'arxiu", "restore_extracting": "Extracció dels fitxers necessaris de l'arxiu...",
"restore_failed": "No s'ha pogut restaurar el sistema", "restore_failed": "No s'ha pogut restaurar el sistema",
"restore_hook_unavailable": "El script de restauració «{part}» no està disponible en el sistema i tampoc és en l'arxiu", "restore_hook_unavailable": "El script de restauració «{part}» no està disponible en el sistema i tampoc és en l'arxiu",
"restore_may_be_not_enough_disk_space": "Sembla que no hi ha prou espai disponible en el sistema (lliure: {free_space} B, espai necessari: {needed_space} B, marge de seguretat: {margin} B)", "restore_may_be_not_enough_disk_space": "Sembla que no hi ha prou espai disponible en el sistema (lliure: {free_space} B, espai necessari: {needed_space} B, marge de seguretat: {margin} B)",
"restore_not_enough_disk_space": "No hi ha prou espai disponible (espai: {free_space} B, espai necessari: {needed_space} B, marge de seguretat: {margin} B)", "restore_not_enough_disk_space": "No hi ha prou espai disponible (espai: {free_space} B, espai necessari: {needed_space} B, marge de seguretat: {margin} B)",
"restore_nothings_done": "No s'ha restaurat res", "restore_nothings_done": "No s'ha restaurat res",
"restore_removing_tmp_dir_failed": "No s'ha pogut eliminar un directori temporal antic", "restore_removing_tmp_dir_failed": "No s'ha pogut eliminar un directori temporal antic",
"restore_running_app_script": "Restaurant l'aplicació «{app}»", "restore_running_app_script": "Restaurant l'aplicació «{app}»...",
"restore_running_hooks": "Execució dels hooks de restauració", "restore_running_hooks": "Execució dels hooks de restauració...",
"restore_system_part_failed": "No s'ha pogut restaurar la part «{part}» del sistema", "restore_system_part_failed": "No s'ha pogut restaurar la part «{part}» del sistema",
"root_password_desynchronized": "S'ha canviat la contrasenya d'administració, però YunoHost no ha pogut propagar-ho cap a la contrasenya root!", "root_password_desynchronized": "S'ha canviat la contrasenya d'administració, però YunoHost no ha pogut propagar-ho cap a la contrasenya root!",
"root_password_replaced_by_admin_password": "La contrasenya root s'ha substituït per la contrasenya d'administració.", "root_password_replaced_by_admin_password": "La contrasenya root s'ha substituït per la contrasenya d'administració.",
@ -319,13 +316,13 @@
"system_upgraded": "S'ha actualitzat el sistema", "system_upgraded": "S'ha actualitzat el sistema",
"system_username_exists": "El nom d'usuari ja existeix en la llista d'usuaris de sistema", "system_username_exists": "El nom d'usuari ja existeix en la llista d'usuaris de sistema",
"this_action_broke_dpkg": "Aquesta acció a trencat dpkg/APT (els gestors de paquets del sistema)... Podeu intentar resoldre el problema connectant-vos amb SSH i executant «sudo apt install --fix-broken» i/o «sudo dpkg --configure -a».", "this_action_broke_dpkg": "Aquesta acció a trencat dpkg/APT (els gestors de paquets del sistema)... Podeu intentar resoldre el problema connectant-vos amb SSH i executant «sudo apt install --fix-broken» i/o «sudo dpkg --configure -a».",
"tools_upgrade_at_least_one": "Especifiqueu «--apps», o «--system»", "tools_upgrade_at_least_one": "Especifiqueu «apps», o «system»",
"tools_upgrade_cant_both": "No es poden actualitzar tant el sistema com les aplicacions al mateix temps", "tools_upgrade_cant_both": "No es poden actualitzar tant el sistema com les aplicacions al mateix temps",
"tools_upgrade_cant_hold_critical_packages": "No es poden mantenir els paquets crítics", "tools_upgrade_cant_hold_critical_packages": "No es poden mantenir els paquets crítics...",
"tools_upgrade_cant_unhold_critical_packages": "No es poden deixar de mantenir els paquets crítics", "tools_upgrade_cant_unhold_critical_packages": "No es poden deixar de mantenir els paquets crítics...",
"tools_upgrade_regular_packages": "Actualitzant els paquets «normals» (no relacionats amb YunoHost)", "tools_upgrade_regular_packages": "Actualitzant els paquets «normals» (no relacionats amb YunoHost)...",
"tools_upgrade_regular_packages_failed": "No s'han pogut actualitzar els paquets següents: {packages_list}", "tools_upgrade_regular_packages_failed": "No s'han pogut actualitzar els paquets següents: {packages_list}",
"tools_upgrade_special_packages": "Actualitzant els paquets «especials» (relacionats amb YunoHost)", "tools_upgrade_special_packages": "Actualitzant els paquets «especials» (relacionats amb YunoHost)...",
"tools_upgrade_special_packages_explanation": "Aquesta actualització especial continuarà en segon pla. No comenceu cap altra acció al servidor en els pròxims ~10 minuts (depèn de la velocitat del maquinari). Després d'això, pot ser que us hagueu de tornar a connectar a la interfície d'administració. Els registres de l'actualització estaran disponibles a Eines → Registres (a la interfície d'administració) o utilitzant «yunohost log list» (des de la línia d'ordres).", "tools_upgrade_special_packages_explanation": "Aquesta actualització especial continuarà en segon pla. No comenceu cap altra acció al servidor en els pròxims ~10 minuts (depèn de la velocitat del maquinari). Després d'això, pot ser que us hagueu de tornar a connectar a la interfície d'administració. Els registres de l'actualització estaran disponibles a Eines → Registres (a la interfície d'administració) o utilitzant «yunohost log list» (des de la línia d'ordres).",
"tools_upgrade_special_packages_completed": "Actualització dels paquets YunoHost acabada.\nPremeu [Enter] per tornar a la línia d'ordres", "tools_upgrade_special_packages_completed": "Actualització dels paquets YunoHost acabada.\nPremeu [Enter] per tornar a la línia d'ordres",
"unbackup_app": "{app} no es guardarà", "unbackup_app": "{app} no es guardarà",
@ -345,7 +342,7 @@
"user_creation_failed": "No s'ha pogut crear l'usuari {user}: {error}", "user_creation_failed": "No s'ha pogut crear l'usuari {user}: {error}",
"user_deleted": "S'ha suprimit l'usuari", "user_deleted": "S'ha suprimit l'usuari",
"user_deletion_failed": "No s'ha pogut suprimir l'usuari {user}: {error}", "user_deletion_failed": "No s'ha pogut suprimir l'usuari {user}: {error}",
"user_home_creation_failed": "No s'ha pogut crear la carpeta personal «home» per l'usuari", "user_home_creation_failed": "No s'ha pogut crear la carpeta personal «{home}» per l'usuari",
"user_unknown": "Usuari desconegut: {user}", "user_unknown": "Usuari desconegut: {user}",
"user_update_failed": "No s'ha pogut actualitzar l'usuari {user}: {error}", "user_update_failed": "No s'ha pogut actualitzar l'usuari {user}: {error}",
"user_updated": "S'ha canviat la informació de l'usuari", "user_updated": "S'ha canviat la informació de l'usuari",
@ -472,7 +469,7 @@
"diagnosis_http_unreachable": "Sembla que el domini {domain} no és accessible a través de HTTP des de fora de la xarxa local.", "diagnosis_http_unreachable": "Sembla que el domini {domain} no és accessible a través de HTTP des de fora de la xarxa local.",
"diagnosis_unknown_categories": "Les següents categories són desconegudes: {categories}", "diagnosis_unknown_categories": "Les següents categories són desconegudes: {categories}",
"apps_catalog_init_success": "S'ha iniciat el sistema de catàleg d'aplicacions!", "apps_catalog_init_success": "S'ha iniciat el sistema de catàleg d'aplicacions!",
"apps_catalog_updating": "S'està actualitzant el catàleg d'aplicacions", "apps_catalog_updating": "S'està actualitzant el catàleg d'aplicacions...",
"apps_catalog_failed_to_download": "No s'ha pogut descarregar el catàleg d'aplicacions {apps_catalog}: {error}", "apps_catalog_failed_to_download": "No s'ha pogut descarregar el catàleg d'aplicacions {apps_catalog}: {error}",
"apps_catalog_obsolete_cache": "La memòria cau del catàleg d'aplicacions és buida o obsoleta.", "apps_catalog_obsolete_cache": "La memòria cau del catàleg d'aplicacions és buida o obsoleta.",
"apps_catalog_update_success": "S'ha actualitzat el catàleg d'aplicacions!", "apps_catalog_update_success": "S'ha actualitzat el catàleg d'aplicacions!",
@ -485,14 +482,12 @@
"diagnosis_no_cache": "Encara no hi ha memòria cau pel diagnòstic de la categoria «{category}»", "diagnosis_no_cache": "Encara no hi ha memòria cau pel diagnòstic de la categoria «{category}»",
"diagnosis_http_timeout": "S'ha exhaurit el temps d'esperar intentant connectar amb el servidor des de l'exterior.<br>1. La causa més probable per a aquest problema és que el port 80 (i 443) <a href='https://yunohost.org/isp_box_config'>no reenvien correctament cap al vostre servidor</a>.<br>2. També us hauríeu d'assegurar que el servei nginx estigui funcionant<br>3. En configuracions més complexes: assegureu-vos que no hi ha cap tallafoc o reverse-proxy interferint.", "diagnosis_http_timeout": "S'ha exhaurit el temps d'esperar intentant connectar amb el servidor des de l'exterior.<br>1. La causa més probable per a aquest problema és que el port 80 (i 443) <a href='https://yunohost.org/isp_box_config'>no reenvien correctament cap al vostre servidor</a>.<br>2. També us hauríeu d'assegurar que el servei nginx estigui funcionant<br>3. En configuracions més complexes: assegureu-vos que no hi ha cap tallafoc o reverse-proxy interferint.",
"diagnosis_http_connection_error": "Error de connexió: no s'ha pogut connectar amb el domini demanat, segurament és inaccessible.", "diagnosis_http_connection_error": "Error de connexió: no s'ha pogut connectar amb el domini demanat, segurament és inaccessible.",
"yunohost_postinstall_end_tip": "S'ha completat la post-instal·lació. Per acabar la configuració, considereu:\n - afegir un primer usuari a través de la secció «Usuaris» a la pàgina web d'administració (o emprant «yunohost user create <username>» a la línia d'ordres);\n - diagnosticar possibles problemes a través de la secció «Diagnòstics» a la pàgina web d'administració (o emprant «yunohost diagnosis run» a la línia d'ordres);\n - llegir les seccions «Finalizing your setup» i «Getting to know Yunohost» a la documentació per administradors: https://yunohost.org/admindoc.", "yunohost_postinstall_end_tip": "S'ha completat la post-instal·lació. Per acabar la configuració, considereu:\n - afegir un primer usuari a través de la secció «Usuaris» a la pàgina web d'administració (o emprant «yunohost user create <username>» a la línia d'ordres);\n - diagnosticar possibles problemes a través de la secció «Diagnòstics» a la pàgina web d'administració (o emprant «yunohost diagnosis run» a la línia d'ordres);\n - llegir les seccions «Finalizing your setup» i «Getting to know YunoHost» a la documentació per administradors: https://yunohost.org/admindoc.",
"diagnosis_services_running": "El servei {service} s'està executant!", "diagnosis_services_running": "El servei {service} s'està executant!",
"diagnosis_services_conf_broken": "La configuració pel servei {service} està trencada!", "diagnosis_services_conf_broken": "La configuració pel servei {service} està trencada!",
"diagnosis_ports_needed_by": "És necessari exposar aquest port per a les funcions {category} (servei {service})", "diagnosis_ports_needed_by": "És necessari exposar aquest port per a les funcions {category} (servei {service})",
"global_settings_setting_pop3_enabled": "Activa el protocol POP3 per al servidor de correu", "global_settings_setting_pop3_enabled": "Activa el protocol POP3 per al servidor de correu",
"log_app_action_run": "Executa l'acció de l'aplicació «{}»", "log_app_action_run": "Executa l'acció de l'aplicació «{}»",
"log_app_config_show_panel": "Mostra el taulell de configuració de l'aplicació «{}»",
"log_app_config_apply": "Afegeix la configuració a l'aplicació «{}»",
"diagnosis_never_ran_yet": "Sembla que el servidor s'ha configurat recentment i encara no hi cap informe de diagnòstic per mostrar. S'ha d'executar un diagnòstic complet primer, ja sigui des de la pàgina web d'administració o utilitzant la comanda «yunohost diagnosis run» al terminal.", "diagnosis_never_ran_yet": "Sembla que el servidor s'ha configurat recentment i encara no hi cap informe de diagnòstic per mostrar. S'ha d'executar un diagnòstic complet primer, ja sigui des de la pàgina web d'administració o utilitzant la comanda «yunohost diagnosis run» al terminal.",
"diagnosis_description_web": "Web", "diagnosis_description_web": "Web",
"diagnosis_basesystem_hardware": "L'arquitectura del maquinari del servidor és {virt} {arch}", "diagnosis_basesystem_hardware": "L'arquitectura del maquinari del servidor és {virt} {arch}",

View file

@ -1 +1 @@
{} {}

View file

@ -11,7 +11,6 @@
"action_invalid": "Nesprávné akce '{action}'", "action_invalid": "Nesprávné akce '{action}'",
"aborting": "Zrušeno.", "aborting": "Zrušeno.",
"app_change_url_identical_domains": "Stará a nová doména/url_cesta jsou totožné ('{domain}{path}'), nebudou provedeny žádné změny.", "app_change_url_identical_domains": "Stará a nová doména/url_cesta jsou totožné ('{domain}{path}'), nebudou provedeny žádné změny.",
"app_change_url_failed_nginx_reload": "Nepodařilo se znovunačís NGINX. Následuje výpis příkazu 'nginx -t':\n{nginx_errors}",
"app_argument_invalid": "Vyberte správnou hodnotu pro argument '{name}': {error}", "app_argument_invalid": "Vyberte správnou hodnotu pro argument '{name}': {error}",
"app_argument_choice_invalid": "Vyberte jednu z možností '{choices}' pro argument'{name}'", "app_argument_choice_invalid": "Vyberte jednu z možností '{choices}' pro argument'{name}'",
"app_already_up_to_date": "{app} aplikace je/jsou aktuální", "app_already_up_to_date": "{app} aplikace je/jsou aktuální",
@ -55,7 +54,7 @@
"global_settings_setting_smtp_relay_password": "SMTP relay heslo uživatele/hostitele", "global_settings_setting_smtp_relay_password": "SMTP relay heslo uživatele/hostitele",
"global_settings_setting_smtp_relay_user": "SMTP relay uživatelské jméno/účet", "global_settings_setting_smtp_relay_user": "SMTP relay uživatelské jméno/účet",
"global_settings_setting_smtp_relay_port": "SMTP relay port", "global_settings_setting_smtp_relay_port": "SMTP relay port",
"global_settings_setting_smtp_relay_host": "Použít SMTP relay hostitele pro odesílání emailů místo této Yunohost instance. Užitečné v různých situacích: port 25 je blokován vaším ISP nebo VPS poskytovatelem, IP adresa je na blacklistu (např. DUHL), nemůžete nastavit reverzní DNS záznam nebo tento server není přímo připojen do internetu a vy chcete použít jiný server k odesílání emailů.", "global_settings_setting_smtp_relay_host": "Použít SMTP relay hostitele pro odesílání emailů místo této YunoHost instance. Užitečné v různých situacích: port 25 je blokován vaším ISP nebo VPS poskytovatelem, IP adresa je na blacklistu (např. DUHL), nemůžete nastavit reverzní DNS záznam nebo tento server není přímo připojen do internetu a vy chcete použít jiný server k odesílání emailů.",
"global_settings_setting_smtp_allow_ipv6": "Povolit použití IPv6 pro příjem a odesílání emailů", "global_settings_setting_smtp_allow_ipv6": "Povolit použití IPv6 pro příjem a odesílání emailů",
"global_settings_setting_ssowat_panel_overlay_enabled": "Povolit SSOwat překryvný panel", "global_settings_setting_ssowat_panel_overlay_enabled": "Povolit SSOwat překryvný panel",
"global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Povolit použití (zastaralého) DSA klíče hostitele pro konfiguraci SSH služby", "global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Povolit použití (zastaralého) DSA klíče hostitele pro konfiguraci SSH služby",

View file

@ -47,9 +47,8 @@
"domain_dyndns_root_unknown": "Unbekannte DynDNS Hauptdomain", "domain_dyndns_root_unknown": "Unbekannte DynDNS Hauptdomain",
"domain_exists": "Die Domäne existiert bereits", "domain_exists": "Die Domäne existiert bereits",
"domain_uninstall_app_first": "Diese Applikationen sind noch auf Ihrer Domäne installiert; \n{apps}\n\nBitte deinstallieren Sie sie mit dem Befehl 'yunohost app remove the_app_id' oder verschieben Sie sie mit 'yunohost app change-url the_app_id'", "domain_uninstall_app_first": "Diese Applikationen sind noch auf Ihrer Domäne installiert; \n{apps}\n\nBitte deinstallieren Sie sie mit dem Befehl 'yunohost app remove the_app_id' oder verschieben Sie sie mit 'yunohost app change-url the_app_id'",
"domain_unknown": "Unbekannte Domain",
"done": "Erledigt", "done": "Erledigt",
"downloading": "Wird heruntergeladen", "downloading": "Wird heruntergeladen...",
"dyndns_ip_update_failed": "Konnte die IP-Adresse für DynDNS nicht aktualisieren", "dyndns_ip_update_failed": "Konnte die IP-Adresse für DynDNS nicht aktualisieren",
"dyndns_ip_updated": "Aktualisierung Ihrer IP-Adresse bei DynDNS", "dyndns_ip_updated": "Aktualisierung Ihrer IP-Adresse bei DynDNS",
"dyndns_key_generating": "Generierung des DNS-Schlüssels..., das könnte eine Weile dauern.", "dyndns_key_generating": "Generierung des DNS-Schlüssels..., das könnte eine Weile dauern.",
@ -92,8 +91,8 @@
"restore_failed": "Das System konnte nicht wiederhergestellt werden", "restore_failed": "Das System konnte nicht wiederhergestellt werden",
"restore_hook_unavailable": "Das Wiederherstellungsskript für '{part}' steht weder in Ihrem System noch im Archiv zur Verfügung", "restore_hook_unavailable": "Das Wiederherstellungsskript für '{part}' steht weder in Ihrem System noch im Archiv zur Verfügung",
"restore_nothings_done": "Nichts wurde wiederhergestellt", "restore_nothings_done": "Nichts wurde wiederhergestellt",
"restore_running_app_script": "App '{app}' wird wiederhergestellt", "restore_running_app_script": "App '{app}' wird wiederhergestellt...",
"restore_running_hooks": "Wiederherstellung wird gestartet", "restore_running_hooks": "Wiederherstellung wird gestartet...",
"service_add_failed": "Der Dienst '{service}' konnte nicht hinzugefügt werden", "service_add_failed": "Der Dienst '{service}' konnte nicht hinzugefügt werden",
"service_added": "Der Dienst '{service}' wurde erfolgreich hinzugefügt", "service_added": "Der Dienst '{service}' wurde erfolgreich hinzugefügt",
"service_already_started": "Der Dienst '{service}' läuft bereits", "service_already_started": "Der Dienst '{service}' läuft bereits",
@ -140,7 +139,6 @@
"app_not_properly_removed": "{app} wurde nicht ordnungsgemäß entfernt", "app_not_properly_removed": "{app} wurde nicht ordnungsgemäß entfernt",
"not_enough_disk_space": "Nicht genügend Speicherplatz auf '{path}' frei", "not_enough_disk_space": "Nicht genügend Speicherplatz auf '{path}' frei",
"backup_creation_failed": "Konnte Backup-Archiv nicht erstellen", "backup_creation_failed": "Konnte Backup-Archiv nicht erstellen",
"pattern_positive_number": "Muss eine positive Zahl sein",
"app_not_correctly_installed": "{app} scheint nicht korrekt installiert zu sein", "app_not_correctly_installed": "{app} scheint nicht korrekt installiert zu sein",
"app_requirements_checking": "Überprüfe notwendige Pakete für {app}...", "app_requirements_checking": "Überprüfe notwendige Pakete für {app}...",
"app_requirements_unmeet": "Anforderungen für {app} werden nicht erfüllt, das Paket {pkgname} ({version}) muss {spec} sein", "app_requirements_unmeet": "Anforderungen für {app} werden nicht erfüllt, das Paket {pkgname} ({version}) muss {spec} sein",
@ -170,7 +168,6 @@
"certmanager_unable_to_parse_self_CA_name": "Der Name der Zertifizierungsstelle für selbstsignierte Zertifikate konnte nicht aufgelöst werden (Datei: {file})", "certmanager_unable_to_parse_self_CA_name": "Der Name der Zertifizierungsstelle für selbstsignierte Zertifikate konnte nicht aufgelöst werden (Datei: {file})",
"domain_hostname_failed": "Sie können keinen neuen Hostnamen verwenden. Das kann zukünftige Probleme verursachen (es kann auch sein, dass es funktioniert).", "domain_hostname_failed": "Sie können keinen neuen Hostnamen verwenden. Das kann zukünftige Probleme verursachen (es kann auch sein, dass es funktioniert).",
"app_already_installed_cant_change_url": "Diese Applikation ist bereits installiert. Die URL kann durch diese Funktion nicht modifiziert werden. Überprüfe ob `app changeurl` verfügbar ist.", "app_already_installed_cant_change_url": "Diese Applikation ist bereits installiert. Die URL kann durch diese Funktion nicht modifiziert werden. Überprüfe ob `app changeurl` verfügbar ist.",
"app_change_url_failed_nginx_reload": "NGINX konnte nicht neu gestartet werden. Hier ist der Output von 'nginx -t':\n{nginx_errors}",
"app_change_url_identical_domains": "Die alte und neue domain/url_path sind identisch: ('{domain} {path}'). Es gibt nichts zu tun.", "app_change_url_identical_domains": "Die alte und neue domain/url_path sind identisch: ('{domain} {path}'). Es gibt nichts zu tun.",
"app_already_up_to_date": "{app} ist bereits aktuell", "app_already_up_to_date": "{app} ist bereits aktuell",
"backup_abstract_method": "Diese Backup-Methode wird noch nicht unterstützt", "backup_abstract_method": "Diese Backup-Methode wird noch nicht unterstützt",
@ -241,10 +238,10 @@
"log_operation_unit_unclosed_properly": "Die Operationseinheit wurde nicht richtig geschlossen", "log_operation_unit_unclosed_properly": "Die Operationseinheit wurde nicht richtig geschlossen",
"global_settings_setting_security_postfix_compatibility": "Kompatibilitäts- vs. Sicherheits-Kompromiss für den Postfix-Server. Betrifft die Ciphers (und andere sicherheitsrelevante Aspekte)", "global_settings_setting_security_postfix_compatibility": "Kompatibilitäts- vs. Sicherheits-Kompromiss für den Postfix-Server. Betrifft die Ciphers (und andere sicherheitsrelevante Aspekte)",
"global_settings_unknown_type": "Unerwartete Situation, die Einstellung {setting} scheint den Typ {unknown_type} zu haben, ist aber kein vom System unterstützter Typ.", "global_settings_unknown_type": "Unerwartete Situation, die Einstellung {setting} scheint den Typ {unknown_type} zu haben, ist aber kein vom System unterstützter Typ.",
"dpkg_is_broken": "Du kannst das gerade nicht tun, weil dpkg/APT (der Systempaketmanager) in einem defekten Zustand zu sein scheint.... Du kannst versuchen, dieses Problem zu lösen, indem du dich über SSH verbindest und `sudo apt install --fix-broken` sowie/oder `sudo dpkg --configure -a` ausführst.", "dpkg_is_broken": "Du kannst das gerade nicht tun, weil dpkg/APT (der Systempaketmanager) in einem defekten Zustand zu sein scheint... Du kannst versuchen, dieses Problem zu lösen, indem du dich über SSH verbindest und `sudo apt install --fix-broken` sowie/oder `sudo dpkg --configure -a` ausführst.",
"global_settings_unknown_setting_from_settings_file": "Unbekannter Schlüssel in den Einstellungen: '{setting_key}', verwerfen und speichern in /etc/yunohost/settings-unknown.json", "global_settings_unknown_setting_from_settings_file": "Unbekannter Schlüssel in den Einstellungen: '{setting_key}', verwerfen und speichern in /etc/yunohost/settings-unknown.json",
"log_link_to_log": "Vollständiges Log dieser Operation: '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>'", "log_link_to_log": "Vollständiges Log dieser Operation: '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>'",
"log_help_to_get_log": "Um das Protokoll der Operation '{desc}' anzuzeigen, verwenden Sie den Befehl 'yunohost log show {name}{name}'", "log_help_to_get_log": "Um das Protokoll der Operation '{desc}' anzuzeigen, verwenden Sie den Befehl 'yunohost log show {name}'",
"global_settings_setting_security_nginx_compatibility": "Kompatibilitäts- vs. Sicherheits-Kompromiss für den Webserver NGINX. Betrifft die Ciphers (und andere sicherheitsrelevante Aspekte)", "global_settings_setting_security_nginx_compatibility": "Kompatibilitäts- vs. Sicherheits-Kompromiss für den Webserver NGINX. Betrifft die Ciphers (und andere sicherheitsrelevante Aspekte)",
"global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Erlaubt die Verwendung eines (veralteten) DSA-Hostkeys für die SSH-Daemon-Konfiguration", "global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Erlaubt die Verwendung eines (veralteten) DSA-Hostkeys für die SSH-Daemon-Konfiguration",
"log_app_remove": "Entferne die Applikation '{}'", "log_app_remove": "Entferne die Applikation '{}'",
@ -279,7 +276,7 @@
"diagnosis_basesystem_ynh_main_version": "Server läuft YunoHost {main_version} ({repo})", "diagnosis_basesystem_ynh_main_version": "Server läuft YunoHost {main_version} ({repo})",
"diagnosis_basesystem_ynh_inconsistent_versions": "Sie verwenden inkonsistente Versionen der YunoHost-Pakete... wahrscheinlich wegen eines fehlgeschlagenen oder teilweisen Upgrades.", "diagnosis_basesystem_ynh_inconsistent_versions": "Sie verwenden inkonsistente Versionen der YunoHost-Pakete... wahrscheinlich wegen eines fehlgeschlagenen oder teilweisen Upgrades.",
"apps_catalog_init_success": "App-Katalogsystem initialisiert!", "apps_catalog_init_success": "App-Katalogsystem initialisiert!",
"apps_catalog_updating": "Aktualisierung des Applikationskatalogs", "apps_catalog_updating": "Aktualisierung des Applikationskatalogs...",
"apps_catalog_failed_to_download": "Der {apps_catalog} App-Katalog kann nicht heruntergeladen werden: {error}", "apps_catalog_failed_to_download": "Der {apps_catalog} App-Katalog kann nicht heruntergeladen werden: {error}",
"apps_catalog_obsolete_cache": "Der Cache des App-Katalogs ist leer oder veraltet.", "apps_catalog_obsolete_cache": "Der Cache des App-Katalogs ist leer oder veraltet.",
"apps_catalog_update_success": "Der Apps-Katalog wurde aktualisiert!", "apps_catalog_update_success": "Der Apps-Katalog wurde aktualisiert!",
@ -432,9 +429,9 @@
"additional_urls_already_removed": "Zusätzliche URL '{url}' bereits entfernt in der zusätzlichen URL für Berechtigung '{permission}'", "additional_urls_already_removed": "Zusätzliche URL '{url}' bereits entfernt in der zusätzlichen URL für Berechtigung '{permission}'",
"app_label_deprecated": "Dieser Befehl ist veraltet! Bitte nutzen Sie den neuen Befehl 'yunohost user permission update' um das Applabel zu verwalten.", "app_label_deprecated": "Dieser Befehl ist veraltet! Bitte nutzen Sie den neuen Befehl 'yunohost user permission update' um das Applabel zu verwalten.",
"diagnosis_http_hairpinning_issue_details": "Das ist wahrscheinlich aufgrund Ihrer ISP Box / Router. Als Konsequenz können Personen von ausserhalb Ihres Netzwerkes aber nicht von innerhalb Ihres lokalen Netzwerkes (wie wahrscheinlich Sie selber?) wie gewohnt auf Ihren Server zugreifen, wenn Sie ihre Domäne oder Ihre öffentliche IP verwenden. Sie können die Situation wahrscheinlich verbessern, indem Sie ein einen Blick in <a href='https://yunohost.org/dns_local_network'>https://yunohost.org/dns_local_network</a> werfen", "diagnosis_http_hairpinning_issue_details": "Das ist wahrscheinlich aufgrund Ihrer ISP Box / Router. Als Konsequenz können Personen von ausserhalb Ihres Netzwerkes aber nicht von innerhalb Ihres lokalen Netzwerkes (wie wahrscheinlich Sie selber?) wie gewohnt auf Ihren Server zugreifen, wenn Sie ihre Domäne oder Ihre öffentliche IP verwenden. Sie können die Situation wahrscheinlich verbessern, indem Sie ein einen Blick in <a href='https://yunohost.org/dns_local_network'>https://yunohost.org/dns_local_network</a> werfen",
"diagnosis_http_nginx_conf_not_up_to_date": "Jemand hat anscheinend die Konfiguration von Nginx manuell geändert. Diese Änderung verhindert, dass Yunohost eine Diagnose durchführen kann, wenn er via HTTP erreichbar ist.", "diagnosis_http_nginx_conf_not_up_to_date": "Jemand hat anscheinend die Konfiguration von Nginx manuell geändert. Diese Änderung verhindert, dass YunoHost eine Diagnose durchführen kann, wenn er via HTTP erreichbar ist.",
"diagnosis_http_bad_status_code": "Anscheinend beantwortet ein anderes Gerät als Ihr Server die Anfrage (Vielleicht ihr Internetrouter).<br>1. Die häufigste Ursache ist, dass Port 80 (und 443) <a href='https://yunohost.org/isp_box_config'>nicht richtig auf Ihren Server weitergeleitet wird</a>.<br> 2. Bei komplexeren Setups: Vergewissern Sie sich, dass keine Firewall und keine Reverse-Proxy interferieren.", "diagnosis_http_bad_status_code": "Anscheinend beantwortet ein anderes Gerät als Ihr Server die Anfrage (Vielleicht ihr Internetrouter).<br>1. Die häufigste Ursache ist, dass Port 80 (und 443) <a href='https://yunohost.org/isp_box_config'>nicht richtig auf Ihren Server weitergeleitet wird</a>.<br> 2. Bei komplexeren Setups: Vergewissern Sie sich, dass keine Firewall und keine Reverse-Proxy interferieren.",
"diagnosis_never_ran_yet": "Sie haben kürzlich einen neuen Yunohost-Server installiert aber es gibt davon noch keinen Diagnosereport. Sie sollten eine Diagnose anstossen. Sie können das entweder vom Webadmin aus oder in der Kommandozeile machen. In der Kommandozeile verwenden Sie dafür den Befehl 'yunohost diagnosis run'.", "diagnosis_never_ran_yet": "Sie haben kürzlich einen neuen YunoHost-Server installiert aber es gibt davon noch keinen Diagnosereport. Sie sollten eine Diagnose anstossen. Sie können das entweder vom Webadmin aus oder in der Kommandozeile machen. In der Kommandozeile verwenden Sie dafür den Befehl 'yunohost diagnosis run'.",
"diagnosis_http_nginx_conf_not_up_to_date_details": "Um dieses Problem zu beheben, geben Sie in der Kommandozeile <cmd>yunohost tools regen-conf nginx --dry-run --with-diff</cmd> ein. Dieses Tool zeigt ihnen den Unterschied an. Wenn Sie damit einverstanden sind, können Sie mit <cmd>yunohost tools regen-conf nginx --force</cmd> die Änderungen übernehmen.", "diagnosis_http_nginx_conf_not_up_to_date_details": "Um dieses Problem zu beheben, geben Sie in der Kommandozeile <cmd>yunohost tools regen-conf nginx --dry-run --with-diff</cmd> ein. Dieses Tool zeigt ihnen den Unterschied an. Wenn Sie damit einverstanden sind, können Sie mit <cmd>yunohost tools regen-conf nginx --force</cmd> die Änderungen übernehmen.",
"diagnosis_backports_in_sources_list": "Sie haben anscheinend apt (den Paketmanager) für das Backports-Repository konfiguriert. Wir raten strikte davon ab, Pakete aus dem Backports-Repository zu installieren. Diese würden wahrscheinlich zu Instabilitäten und Konflikten führen. Es sei denn, Sie wissen was Sie tun.", "diagnosis_backports_in_sources_list": "Sie haben anscheinend apt (den Paketmanager) für das Backports-Repository konfiguriert. Wir raten strikte davon ab, Pakete aus dem Backports-Repository zu installieren. Diese würden wahrscheinlich zu Instabilitäten und Konflikten führen. Es sei denn, Sie wissen was Sie tun.",
"diagnosis_basesystem_hardware_model": "Das Servermodell ist {model}", "diagnosis_basesystem_hardware_model": "Das Servermodell ist {model}",
@ -442,8 +439,8 @@
"group_user_not_in_group": "Der Benutzer {user} ist nicht in der Gruppe {group}", "group_user_not_in_group": "Der Benutzer {user} ist nicht in der Gruppe {group}",
"group_user_already_in_group": "Der Benutzer {user} ist bereits in der Gruppe {group}", "group_user_already_in_group": "Der Benutzer {user} ist bereits in der Gruppe {group}",
"group_cannot_edit_visitors": "Die Gruppe \"Besucher\" kann nicht manuell editiert werden. Sie ist eine Sondergruppe und repräsentiert anonyme Besucher", "group_cannot_edit_visitors": "Die Gruppe \"Besucher\" kann nicht manuell editiert werden. Sie ist eine Sondergruppe und repräsentiert anonyme Besucher",
"group_cannot_edit_all_users": "Die Gruppe \"all_users\" kann nicht manuell editiert werden. Sie ist eine Sondergruppe die dafür gedacht ist alle Benutzer in Yunohost zu halten", "group_cannot_edit_all_users": "Die Gruppe \"all_users\" kann nicht manuell editiert werden. Sie ist eine Sondergruppe die dafür gedacht ist alle Benutzer in YunoHost zu halten",
"group_already_exist_on_system_but_removing_it": "Die Gruppe {group} existiert bereits in den Systemgruppen, aber Yunohost wird sie entfernen...", "group_already_exist_on_system_but_removing_it": "Die Gruppe {group} existiert bereits in den Systemgruppen, aber YunoHost wird sie entfernen...",
"group_already_exist_on_system": "Die Gruppe {group} existiert bereits in den Systemgruppen", "group_already_exist_on_system": "Die Gruppe {group} existiert bereits in den Systemgruppen",
"group_already_exist": "Die Gruppe {group} existiert bereits", "group_already_exist": "Die Gruppe {group} existiert bereits",
"global_settings_setting_smtp_relay_password": "SMTP Relay Host Passwort", "global_settings_setting_smtp_relay_password": "SMTP Relay Host Passwort",
@ -460,8 +457,6 @@
"log_backup_restore_app": "'{}' aus einem Backup-Archiv wiederherstellen", "log_backup_restore_app": "'{}' aus einem Backup-Archiv wiederherstellen",
"log_backup_restore_system": "System aus einem Backup-Archiv wiederherstellen", "log_backup_restore_system": "System aus einem Backup-Archiv wiederherstellen",
"log_available_on_yunopaste": "Das Protokoll ist nun via {url} verfügbar", "log_available_on_yunopaste": "Das Protokoll ist nun via {url} verfügbar",
"log_app_config_apply": "Wende die Konfiguration auf die Applikation '{}' an",
"log_app_config_show_panel": "Zeige das Konfigurations-Panel der Applikation '{}'",
"log_app_action_run": "Führe Aktion der Applikation '{}' aus", "log_app_action_run": "Führe Aktion der Applikation '{}' aus",
"invalid_regex": "Ungültige Regex:'{regex}'", "invalid_regex": "Ungültige Regex:'{regex}'",
"migration_description_0016_php70_to_php73_pools": "Migrieren der php7.0-fpm-Konfigurationsdateien zu php7.3", "migration_description_0016_php70_to_php73_pools": "Migrieren der php7.0-fpm-Konfigurationsdateien zu php7.3",
@ -566,13 +561,13 @@
"regenconf_updated": "Konfiguration aktualisiert für '{category}'", "regenconf_updated": "Konfiguration aktualisiert für '{category}'",
"regenconf_pending_applying": "Wende die anstehende Konfiguration für die Kategorie {category} an...", "regenconf_pending_applying": "Wende die anstehende Konfiguration für die Kategorie {category} an...",
"regenconf_failed": "Konnte die Konfiguration für die Kategorie(n) {categories} nicht neu erstellen", "regenconf_failed": "Konnte die Konfiguration für die Kategorie(n) {categories} nicht neu erstellen",
"regenconf_dry_pending_applying": "Überprüfe die anstehende Konfiguration, welche für die Kategorie {category}' aktualisiert worden wäre", "regenconf_dry_pending_applying": "Überprüfe die anstehende Konfiguration, welche für die Kategorie {category}' aktualisiert worden wäre...",
"regenconf_would_be_updated": "Die Konfiguration wäre für die Kategorie '{category}' aktualisiert worden", "regenconf_would_be_updated": "Die Konfiguration wäre für die Kategorie '{category}' aktualisiert worden",
"restore_system_part_failed": "Die Systemteile '{part}' konnten nicht wiederhergestellt werden", "restore_system_part_failed": "Die Systemteile '{part}' konnten nicht wiederhergestellt werden",
"restore_removing_tmp_dir_failed": "Ein altes, temporäres Directory konnte nicht entfernt werden", "restore_removing_tmp_dir_failed": "Ein altes, temporäres Directory konnte nicht entfernt werden",
"restore_not_enough_disk_space": "Nicht genug Speicher (Speicher: {free_space} B, benötigter Speicher: {needed_space} B, Sicherheitspuffer: {margin} B)", "restore_not_enough_disk_space": "Nicht genug Speicher (Speicher: {free_space} B, benötigter Speicher: {needed_space} B, Sicherheitspuffer: {margin} B)",
"restore_may_be_not_enough_disk_space": "Ihr System scheint nicht genug Speicherplatz zu haben (frei: {free_space} B, benötigter Platz: {needed_space} B, Sicherheitspuffer: {margin} B)", "restore_may_be_not_enough_disk_space": "Ihr System scheint nicht genug Speicherplatz zu haben (frei: {free_space} B, benötigter Platz: {needed_space} B, Sicherheitspuffer: {margin} B)",
"restore_extracting": "Packe die benötigten Dateien aus dem Archiv aus", "restore_extracting": "Packe die benötigten Dateien aus dem Archiv aus...",
"restore_already_installed_apps": "Folgende Apps können nicht wiederhergestellt werden, weil sie schon installiert sind: {apps}", "restore_already_installed_apps": "Folgende Apps können nicht wiederhergestellt werden, weil sie schon installiert sind: {apps}",
"regex_with_only_domain": "Du kannst regex nicht als Domain verwenden, sondern nur als Pfad", "regex_with_only_domain": "Du kannst regex nicht als Domain verwenden, sondern nur als Pfad",
"root_password_desynchronized": "Das Admin-Passwort wurde verändert, aber das Root-Passwort ist immer noch das alte!", "root_password_desynchronized": "Das Admin-Passwort wurde verändert, aber das Root-Passwort ist immer noch das alte!",
@ -617,16 +612,16 @@
"show_tile_cant_be_enabled_for_regex": "Momentan können Sie 'show_tile' nicht aktivieren, weil die URL für die Berechtigung '{permission}' ein regulärer Ausdruck ist", "show_tile_cant_be_enabled_for_regex": "Momentan können Sie 'show_tile' nicht aktivieren, weil die URL für die Berechtigung '{permission}' ein regulärer Ausdruck ist",
"show_tile_cant_be_enabled_for_url_not_defined": "Momentan können Sie 'show_tile' nicht aktivieren, weil Sie zuerst eine URL für die Berechtigung '{permission}' definieren müssen", "show_tile_cant_be_enabled_for_url_not_defined": "Momentan können Sie 'show_tile' nicht aktivieren, weil Sie zuerst eine URL für die Berechtigung '{permission}' definieren müssen",
"tools_upgrade_regular_packages_failed": "Konnte für die folgenden Pakete das Upgrade nicht durchführen: {packages_list}", "tools_upgrade_regular_packages_failed": "Konnte für die folgenden Pakete das Upgrade nicht durchführen: {packages_list}",
"tools_upgrade_regular_packages": "Momentan werden Upgrades für das System (YunoHost-unabhängige) Pakete durchgeführt", "tools_upgrade_regular_packages": "Momentan werden Upgrades für das System (YunoHost-unabhängige) Pakete durchgeführt...",
"tools_upgrade_cant_unhold_critical_packages": "Konnte für die kritischen Pakete das Flag 'hold' nicht aufheben", "tools_upgrade_cant_unhold_critical_packages": "Konnte für die kritischen Pakete das Flag 'hold' nicht aufheben...",
"tools_upgrade_cant_hold_critical_packages": "Konnte für die kritischen Pakete das Flag 'hold' nicht setzen", "tools_upgrade_cant_hold_critical_packages": "Konnte für die kritischen Pakete das Flag 'hold' nicht setzen...",
"tools_upgrade_cant_both": "Kann das Upgrade für das System und die Applikation nicht gleichzeitig durchführen", "tools_upgrade_cant_both": "Kann das Upgrade für das System und die Applikation nicht gleichzeitig durchführen",
"tools_upgrade_at_least_one": "Bitte geben Sie '--apps' oder '--system' an", "tools_upgrade_at_least_one": "Bitte geben Sie '--apps' oder '--system' an",
"this_action_broke_dpkg": "Diese Aktion hat unkonfigurierte Pakete verursacht, welche durch dpkg/apt (die Paketverwaltungen dieses Systems) zurückgelassen wurden... Sie können versuchen dieses Problem zu lösen, indem Sie 'sudo apt install --fix-broken' und/oder 'sudo dpkg --configure -a' ausführen.", "this_action_broke_dpkg": "Diese Aktion hat unkonfigurierte Pakete verursacht, welche durch dpkg/apt (die Paketverwaltungen dieses Systems) zurückgelassen wurden... Sie können versuchen dieses Problem zu lösen, indem Sie 'sudo apt install --fix-broken' und/oder 'sudo dpkg --configure -a' ausführen.",
"update_apt_cache_failed": "Kann den Cache von APT (Debians Paketmanager) nicht aktualisieren. Hier ist ein Auszug aus den sources.list-Zeilen, die helfen könnten, das Problem zu identifizieren:\n{sourceslist}", "update_apt_cache_failed": "Kann den Cache von APT (Debians Paketmanager) nicht aktualisieren. Hier ist ein Auszug aus den sources.list-Zeilen, die helfen könnten, das Problem zu identifizieren:\n{sourceslist}",
"tools_upgrade_special_packages_completed": "YunoHost-Paketupdate beendet.\nDrücke [Enter], um zurück zur Kommandoziele zu kommen", "tools_upgrade_special_packages_completed": "YunoHost-Paketupdate beendet.\nDrücke [Enter], um zurück zur Kommandoziele zu kommen",
"tools_upgrade_special_packages_explanation": "Das Upgrade \"special\" wird im Hintergrund ausgeführt. Bitte starten Sie keine anderen Aktionen auf Ihrem Server für die nächsten ~10 Minuten. Die Dauer ist abhängig von der Geschwindigkeit Ihres Servers. Nach dem Upgrade müssen Sie sich eventuell erneut in das Adminportal einloggen. Upgrade-Logs sind im Adminbereich unter Tools → Log verfügbar. Alternativ können Sie in der Befehlszeile 'yunohost log list' eingeben.", "tools_upgrade_special_packages_explanation": "Das Upgrade \"special\" wird im Hintergrund ausgeführt. Bitte starten Sie keine anderen Aktionen auf Ihrem Server für die nächsten ~10 Minuten. Die Dauer ist abhängig von der Geschwindigkeit Ihres Servers. Nach dem Upgrade müssen Sie sich eventuell erneut in das Adminportal einloggen. Upgrade-Logs sind im Adminbereich unter Tools → Log verfügbar. Alternativ können Sie in der Befehlszeile 'yunohost log list' eingeben.",
"tools_upgrade_special_packages": "\"special\" (YunoHost-bezogene) Pakete werden jetzt aktualisiert", "tools_upgrade_special_packages": "\"special\" (YunoHost-bezogene) Pakete werden jetzt aktualisiert...",
"unknown_main_domain_path": "Unbekannte:r Domain oder Pfad für '{app}'. Du musst eine Domain und einen Pfad setzen, um die URL für Berechtigungen zu setzen.", "unknown_main_domain_path": "Unbekannte:r Domain oder Pfad für '{app}'. Du musst eine Domain und einen Pfad setzen, um die URL für Berechtigungen zu setzen.",
"yunohost_postinstall_end_tip": "Post-install ist fertig! Um das Setup abzuschliessen, wird empfohlen:\n - einen ersten Benutzer über den Bereich 'Benutzer*in' im Adminbereich hinzuzufügen (oder mit 'yunohost user create <username>' in der Kommandezeile);\n - mögliche Fehler zu diagnostizieren über den Bereich 'Diagnose' im Adminbereich (oder mit 'yunohost diagnosis run' in der Kommandozeile;\n - Die Abschnitte 'Install YunoHost' und 'Geführte Tour' im Administratorenhandbuch zu lesen: https://yunohost.org/admindoc.", "yunohost_postinstall_end_tip": "Post-install ist fertig! Um das Setup abzuschliessen, wird empfohlen:\n - einen ersten Benutzer über den Bereich 'Benutzer*in' im Adminbereich hinzuzufügen (oder mit 'yunohost user create <username>' in der Kommandezeile);\n - mögliche Fehler zu diagnostizieren über den Bereich 'Diagnose' im Adminbereich (oder mit 'yunohost diagnosis run' in der Kommandozeile;\n - Die Abschnitte 'Install YunoHost' und 'Geführte Tour' im Administratorenhandbuch zu lesen: https://yunohost.org/admindoc.",
"user_already_exists": "Der Benutzer '{user}' ist bereits vorhanden", "user_already_exists": "Der Benutzer '{user}' ist bereits vorhanden",
@ -634,5 +629,6 @@
"global_settings_setting_security_webadmin_allowlist": "IP-Adressen, die auf die Verwaltungsseite zugreifen dürfen. Kommasepariert.", "global_settings_setting_security_webadmin_allowlist": "IP-Adressen, die auf die Verwaltungsseite zugreifen dürfen. Kommasepariert.",
"global_settings_setting_security_webadmin_allowlist_enabled": "Erlaube nur bestimmten IP-Adressen den Zugriff auf die Verwaltungsseite.", "global_settings_setting_security_webadmin_allowlist_enabled": "Erlaube nur bestimmten IP-Adressen den Zugriff auf die Verwaltungsseite.",
"disk_space_not_sufficient_update": "Es ist nicht genügend Speicherplatz frei, um diese Applikation zu aktuallisieren", "disk_space_not_sufficient_update": "Es ist nicht genügend Speicherplatz frei, um diese Applikation zu aktuallisieren",
"disk_space_not_sufficient_install": "Es ist nicht genügend Speicherplatz frei, um diese Applikation zu installieren" "disk_space_not_sufficient_install": "Es ist nicht genügend Speicherplatz frei, um diese Applikation zu installieren",
} "danger": "Warnung:"
}

View file

@ -13,14 +13,17 @@
"app_already_installed": "{app} is already installed", "app_already_installed": "{app} is already installed",
"app_already_installed_cant_change_url": "This app is already installed. The URL cannot be changed just by this function. Check in `app changeurl` if it's available.", "app_already_installed_cant_change_url": "This app is already installed. The URL cannot be changed just by this function. Check in `app changeurl` if it's available.",
"app_already_up_to_date": "{app} is already up-to-date", "app_already_up_to_date": "{app} is already up-to-date",
"app_argument_choice_invalid": "Use one of these choices '{choices}' for the argument '{name}'", "app_argument_choice_invalid": "Use one of these choices '{choices}' for the argument '{name}' instead of '{value}'",
"app_argument_invalid": "Pick a valid value for the argument '{name}': {error}", "app_argument_invalid": "Pick a valid value for the argument '{name}': {error}",
"app_argument_password_help_keep": "Press Enter to keep the current value",
"app_argument_password_help_optional": "Type one space to empty the password",
"app_argument_password_no_default": "Error while parsing password argument '{name}': password argument can't have a default value for security reason", "app_argument_password_no_default": "Error while parsing password argument '{name}': password argument can't have a default value for security reason",
"app_argument_required": "Argument '{name}' is required", "app_argument_required": "Argument '{name}' is required",
"app_change_url_failed_nginx_reload": "Could not reload NGINX. Here is the output of 'nginx -t':\n{nginx_errors}",
"app_change_url_identical_domains": "The old and new domain/url_path are identical ('{domain}{path}'), nothing to do.", "app_change_url_identical_domains": "The old and new domain/url_path are identical ('{domain}{path}'), nothing to do.",
"app_change_url_no_script": "The app '{app_name}' doesn't support URL modification yet. Maybe you should upgrade it.", "app_change_url_no_script": "The app '{app_name}' doesn't support URL modification yet. Maybe you should upgrade it.",
"app_change_url_success": "{app} URL is now {domain}{path}", "app_change_url_success": "{app} URL is now {domain}{path}",
"app_config_unable_to_apply": "Failed to apply config panel values.",
"app_config_unable_to_read": "Failed to read config panel values.",
"app_extraction_failed": "Could not extract the installation files", "app_extraction_failed": "Could not extract the installation files",
"app_full_domain_unavailable": "Sorry, this app must be installed on a domain of its own, but other apps are already installed on the domain '{domain}'. You could use a subdomain dedicated to this app instead.", "app_full_domain_unavailable": "Sorry, this app must be installed on a domain of its own, but other apps are already installed on the domain '{domain}'. You could use a subdomain dedicated to this app instead.",
"app_id_invalid": "Invalid app ID", "app_id_invalid": "Invalid app ID",
@ -139,10 +142,22 @@
"certmanager_self_ca_conf_file_not_found": "Could not find configuration file for self-signing authority (file: {file})", "certmanager_self_ca_conf_file_not_found": "Could not find configuration file for self-signing authority (file: {file})",
"certmanager_unable_to_parse_self_CA_name": "Could not parse name of self-signing authority (file: {file})", "certmanager_unable_to_parse_self_CA_name": "Could not parse name of self-signing authority (file: {file})",
"certmanager_warning_subdomain_dns_record": "Subdomain '{subdomain}' does not resolve to the same IP address as '{domain}'. Some features will not be available until you fix this and regenerate the certificate.", "certmanager_warning_subdomain_dns_record": "Subdomain '{subdomain}' does not resolve to the same IP address as '{domain}'. Some features will not be available until you fix this and regenerate the certificate.",
"config_apply_failed": "Applying the new configuration failed: {error}",
"config_cant_set_value_on_section": "You can't set a single value on an entire config section.",
"config_forbidden_keyword": "The keyword '{keyword}' is reserved, you can't create or use a config panel with a question with this id.",
"config_no_panel": "No config panel found.",
"config_unknown_filter_key": "The filter key '{filter_key}' is incorrect.",
"config_validate_color": "Should be a valid RGB hexadecimal color",
"config_validate_date": "Should be a valid date like in the format YYYY-MM-DD",
"config_validate_email": "Should be a valid email",
"config_validate_time": "Should be a valid time like HH:MM",
"config_validate_url": "Should be a valid web URL",
"config_version_not_supported": "Config panel versions '{version}' are not supported.",
"confirm_app_install_danger": "DANGER! This app is known to be still experimental (if not explicitly not working)! You should probably NOT install it unless you know what you are doing. NO SUPPORT will be provided if this app doesn't work or breaks your system... If you are willing to take that risk anyway, type '{answers}'", "confirm_app_install_danger": "DANGER! This app is known to be still experimental (if not explicitly not working)! You should probably NOT install it unless you know what you are doing. NO SUPPORT will be provided if this app doesn't work or breaks your system... If you are willing to take that risk anyway, type '{answers}'",
"confirm_app_install_thirdparty": "DANGER! This app is not part of YunoHost's app catalog. Installing third-party apps may compromise the integrity and security of your system. You should probably NOT install it unless you know what you are doing. NO SUPPORT will be provided if this app doesn't work or breaks your system... If you are willing to take that risk anyway, type '{answers}'", "confirm_app_install_thirdparty": "DANGER! This app is not part of YunoHost's app catalog. Installing third-party apps may compromise the integrity and security of your system. You should probably NOT install it unless you know what you are doing. NO SUPPORT will be provided if this app doesn't work or breaks your system... If you are willing to take that risk anyway, type '{answers}'",
"confirm_app_install_warning": "Warning: This app may work, but is not well-integrated in YunoHost. Some features such as single sign-on and backup/restore might not be available. Install anyway? [{answers}] ", "confirm_app_install_warning": "Warning: This app may work, but is not well-integrated in YunoHost. Some features such as single sign-on and backup/restore might not be available. Install anyway? [{answers}] ",
"custom_app_url_required": "You must provide a URL to upgrade your custom app {app}", "custom_app_url_required": "You must provide a URL to upgrade your custom app {app}",
"danger": "Danger:",
"diagnosis_apps_allgood": "All installed apps respect basic packaging practices", "diagnosis_apps_allgood": "All installed apps respect basic packaging practices",
"diagnosis_apps_bad_quality": "This application is currently flagged as broken on YunoHost's application catalog. This may be a temporary issue while the maintainers attempt to fix the issue. In the meantime, upgrading this app is disabled.", "diagnosis_apps_bad_quality": "This application is currently flagged as broken on YunoHost's application catalog. This may be a temporary issue while the maintainers attempt to fix the issue. In the meantime, upgrading this app is disabled.",
"diagnosis_apps_broken": "This application is currently flagged as broken on YunoHost's application catalog. This may be a temporary issue while the maintainers attempt to fix the issue. In the meantime, upgrading this app is disabled.", "diagnosis_apps_broken": "This application is currently flagged as broken on YunoHost's application catalog. This may be a temporary issue while the maintainers attempt to fix the issue. In the meantime, upgrading this app is disabled.",
@ -302,7 +317,34 @@
"domain_name_unknown": "Domain '{domain}' unknown", "domain_name_unknown": "Domain '{domain}' unknown",
"domain_remove_confirm_apps_removal": "Removing this domain will remove those applications:\n{apps}\n\nAre you sure you want to do that? [{answers}]", "domain_remove_confirm_apps_removal": "Removing this domain will remove those applications:\n{apps}\n\nAre you sure you want to do that? [{answers}]",
"domain_uninstall_app_first": "Those applications are still installed on your domain:\n{apps}\n\nPlease uninstall them using 'yunohost app remove the_app_id' or move them to another domain using 'yunohost app change-url the_app_id' before proceeding to domain removal", "domain_uninstall_app_first": "Those applications are still installed on your domain:\n{apps}\n\nPlease uninstall them using 'yunohost app remove the_app_id' or move them to another domain using 'yunohost app change-url the_app_id' before proceeding to domain removal",
"domain_unknown": "Unknown domain", "domain_registrar_is_not_configured": "The registrar is not yet configured for domain {domain}.",
"domain_dns_push_not_applicable": "The automatic DNS configuration feature is not applicable to domain {domain}. You should manually configure your DNS records following the documentation at https://yunohost.org/dns_config.",
"domain_dns_push_managed_in_parent_domain": "The automatic DNS configuration feature is managed in the parent domain {parent_domain}.",
"domain_dns_registrar_managed_in_parent_domain": "This domain is a subdomain of {parent_domain_link}. DNS registrar configuration should be managed in {parent_domain}'s configuration panel.",
"domain_dns_registrar_yunohost": "This domain is a nohost.me / nohost.st / ynh.fr and its DNS configuration is therefore automatically handled by YunoHost without any further configuration. (see the 'yunohost dyndns update' command)",
"domain_dns_registrar_not_supported": "YunoHost could not automatically detect the registrar handling this domain. You should manually configure your DNS records following the documentation at https://yunohost.org/dns.",
"domain_dns_registrar_supported": "YunoHost automatically detected that this domain is handled by the registrar **{registrar}**. If you want, YunoHost will automatically configure this DNS zone, if you provide it with the appropriate API credentials. You can find documentation on how to obtain your API credentials on this page: https://yunohost.org/registar_api_{registrar}. (You can also manually configure your DNS records following the documentation at https://yunohost.org/dns )",
"domain_dns_registrar_experimental": "So far, the interface with **{registrar}**'s API has not been properly tested and reviewed by the YunoHost community. Support is **very experimental** - be careful!",
"domain_dns_push_failed_to_authenticate": "Failed to authenticate on registrar's API for domain '{domain}'. Most probably the credentials are incorrect? (Error: {error})",
"domain_dns_push_failed_to_list": "Failed to list current records using the registrar's API: {error}",
"domain_dns_push_already_up_to_date": "Records already up to date, nothing to do.",
"domain_dns_pushing": "Pushing DNS records...",
"domain_dns_push_record_failed": "Failed to {action} record {type}/{name} : {error}",
"domain_dns_push_success": "DNS records updated!",
"domain_dns_push_failed": "Updating the DNS records failed miserably.",
"domain_dns_push_partial_failure": "DNS records partially updated: some warnings/errors were reported.",
"domain_config_features_disclaimer": "So far, enabling/disabling mail or XMPP features only impact the recommended and automatic DNS configuration, not system configurations!",
"domain_config_mail_in": "Incoming emails",
"domain_config_mail_out": "Outgoing emails",
"domain_config_xmpp": "Instant messaging (XMPP)",
"domain_config_auth_token": "Authentication token",
"domain_config_auth_key": "Authentication key",
"domain_config_auth_secret": "Authentication secret",
"domain_config_api_protocol": "API protocol",
"domain_config_auth_entrypoint": "API entry point",
"domain_config_auth_application_key": "Application key",
"domain_config_auth_application_secret": "Application secret key",
"domain_config_auth_consumer_key": "Consumer key",
"domains_available": "Available domains:", "domains_available": "Available domains:",
"done": "Done", "done": "Done",
"downloading": "Downloading...", "downloading": "Downloading...",
@ -324,6 +366,7 @@
"extracting": "Extracting...", "extracting": "Extracting...",
"field_invalid": "Invalid field '{}'", "field_invalid": "Invalid field '{}'",
"file_does_not_exist": "The file {path} does not exist.", "file_does_not_exist": "The file {path} does not exist.",
"file_extension_not_accepted": "Refusing file '{path}' because its extension is not among the accepted extensions: {accept}",
"firewall_reload_failed": "Could not reload the firewall", "firewall_reload_failed": "Could not reload the firewall",
"firewall_reloaded": "Firewall reloaded", "firewall_reloaded": "Firewall reloaded",
"firewall_rules_cmd_failed": "Some firewall rule commands have failed. More info in log.", "firewall_rules_cmd_failed": "Some firewall rule commands have failed. More info in log.",
@ -337,8 +380,8 @@
"global_settings_setting_backup_compress_tar_archives": "When creating new backups, compress the archives (.tar.gz) instead of uncompressed archives (.tar). N.B. : enabling this option means create lighter backup archives, but the initial backup procedure will be significantly longer and heavy on CPU.", "global_settings_setting_backup_compress_tar_archives": "When creating new backups, compress the archives (.tar.gz) instead of uncompressed archives (.tar). N.B. : enabling this option means create lighter backup archives, but the initial backup procedure will be significantly longer and heavy on CPU.",
"global_settings_setting_pop3_enabled": "Enable the POP3 protocol for the mail server", "global_settings_setting_pop3_enabled": "Enable the POP3 protocol for the mail server",
"global_settings_setting_security_experimental_enabled": "Enable experimental security features (don't enable this if you don't know what you're doing!)", "global_settings_setting_security_experimental_enabled": "Enable experimental security features (don't enable this if you don't know what you're doing!)",
"global_settings_setting_security_nginx_redirect_to_https": "Redirect HTTP requests to HTTPs by default (DO NOT TURN OFF unless you really know what you're doing!)",
"global_settings_setting_security_nginx_compatibility": "Compatibility vs. security tradeoff for the web server NGINX. Affects the ciphers (and other security-related aspects)", "global_settings_setting_security_nginx_compatibility": "Compatibility vs. security tradeoff for the web server NGINX. Affects the ciphers (and other security-related aspects)",
"global_settings_setting_security_nginx_redirect_to_https": "Redirect HTTP requests to HTTPs by default (DO NOT TURN OFF unless you really know what you're doing!)",
"global_settings_setting_security_password_admin_strength": "Admin password strength", "global_settings_setting_security_password_admin_strength": "Admin password strength",
"global_settings_setting_security_password_user_strength": "User password strength", "global_settings_setting_security_password_user_strength": "User password strength",
"global_settings_setting_security_postfix_compatibility": "Compatibility vs. security tradeoff for the Postfix server. Affects the ciphers (and other security-related aspects)", "global_settings_setting_security_postfix_compatibility": "Compatibility vs. security tradeoff for the Postfix server. Affects the ciphers (and other security-related aspects)",
@ -380,16 +423,18 @@
"hook_name_unknown": "Unknown hook name '{name}'", "hook_name_unknown": "Unknown hook name '{name}'",
"installation_complete": "Installation completed", "installation_complete": "Installation completed",
"invalid_number": "Must be a number", "invalid_number": "Must be a number",
"invalid_number_min": "Must be greater than {min}",
"invalid_number_max": "Must be lesser than {max}",
"invalid_password": "Invalid password", "invalid_password": "Invalid password",
"invalid_regex": "Invalid regex:'{regex}'", "invalid_regex": "Invalid regex:'{regex}'",
"ip6tables_unavailable": "You cannot play with ip6tables here. You are either in a container or your kernel does not support it", "ip6tables_unavailable": "You cannot play with ip6tables here. You are either in a container or your kernel does not support it",
"iptables_unavailable": "You cannot play with iptables here. You are either in a container or your kernel does not support it", "iptables_unavailable": "You cannot play with iptables here. You are either in a container or your kernel does not support it",
"ldap_server_down": "Unable to reach LDAP server", "ldap_server_down": "Unable to reach LDAP server",
"ldap_server_is_down_restart_it": "The LDAP service is down, attempt to restart it...", "ldap_server_is_down_restart_it": "The LDAP service is down, attempt to restart it...",
"ldap_attribute_already_exists": "LDAP attribute '{attribute}' already exists with value '{value}'",
"log_app_action_run": "Run action of the '{}' app", "log_app_action_run": "Run action of the '{}' app",
"log_app_change_url": "Change the URL of the '{}' app", "log_app_change_url": "Change the URL of the '{}' app",
"log_app_config_apply": "Apply config to the '{}' app", "log_app_config_set": "Apply config to the '{}' app",
"log_app_config_show_panel": "Show the config panel of the '{}' app",
"log_app_install": "Install the '{}' app", "log_app_install": "Install the '{}' app",
"log_app_makedefault": "Make '{}' the default app", "log_app_makedefault": "Make '{}' the default app",
"log_app_remove": "Remove the '{}' app", "log_app_remove": "Remove the '{}' app",
@ -401,12 +446,14 @@
"log_corrupted_md_file": "The YAML metadata file associated with logs is damaged: '{md_file}\nError: {error}'", "log_corrupted_md_file": "The YAML metadata file associated with logs is damaged: '{md_file}\nError: {error}'",
"log_does_exists": "There is no operation log with the name '{log}', use 'yunohost log list' to see all available operation logs", "log_does_exists": "There is no operation log with the name '{log}', use 'yunohost log list' to see all available operation logs",
"log_domain_add": "Add '{}' domain into system configuration", "log_domain_add": "Add '{}' domain into system configuration",
"log_domain_config_set": "Update configuration for domain '{}'",
"log_domain_main_domain": "Make '{}' the main domain", "log_domain_main_domain": "Make '{}' the main domain",
"log_domain_remove": "Remove '{}' domain from system configuration", "log_domain_remove": "Remove '{}' domain from system configuration",
"log_domain_dns_push": "Push DNS records for domain '{}'",
"log_dyndns_subscribe": "Subscribe to a YunoHost subdomain '{}'", "log_dyndns_subscribe": "Subscribe to a YunoHost subdomain '{}'",
"log_dyndns_update": "Update the IP associated with your YunoHost subdomain '{}'", "log_dyndns_update": "Update the IP associated with your YunoHost subdomain '{}'",
"log_help_to_get_failed_log": "The operation '{desc}' could not be completed. Please share the full log of this operation using the command 'yunohost log share {name}' to get help", "log_help_to_get_failed_log": "The operation '{desc}' could not be completed. Please share the full log of this operation using the command 'yunohost log share {name}' to get help",
"log_help_to_get_log": "To view the log of the operation '{desc}', use the command 'yunohost log show {name}{name}'", "log_help_to_get_log": "To view the log of the operation '{desc}', use the command 'yunohost log show {name}'",
"log_letsencrypt_cert_install": "Install a Let's Encrypt certificate on '{}' domain", "log_letsencrypt_cert_install": "Install a Let's Encrypt certificate on '{}' domain",
"log_letsencrypt_cert_renew": "Renew '{}' Let's Encrypt certificate", "log_letsencrypt_cert_renew": "Renew '{}' Let's Encrypt certificate",
"log_link_to_failed_log": "Could not complete the operation '{desc}'. Please provide the full log of this operation by <a href=\"#/tools/logs/{name}\">clicking here</a> to get help", "log_link_to_failed_log": "Could not complete the operation '{desc}'. Please provide the full log of this operation by <a href=\"#/tools/logs/{name}\">clicking here</a> to get help",
@ -529,7 +576,6 @@
"pattern_password": "Must be at least 3 characters long", "pattern_password": "Must be at least 3 characters long",
"pattern_password_app": "Sorry, passwords can not contain the following characters: {forbidden_chars}", "pattern_password_app": "Sorry, passwords can not contain the following characters: {forbidden_chars}",
"pattern_port_or_range": "Must be a valid port number (i.e. 0-65535) or range of ports (e.g. 100:200)", "pattern_port_or_range": "Must be a valid port number (i.e. 0-65535) or range of ports (e.g. 100:200)",
"pattern_positive_number": "Must be a positive number",
"pattern_username": "Must be lower-case alphanumeric and underscore characters only", "pattern_username": "Must be lower-case alphanumeric and underscore characters only",
"permission_already_allowed": "Group '{group}' already has permission '{permission}' enabled", "permission_already_allowed": "Group '{group}' already has permission '{permission}' enabled",
"permission_already_disallowed": "Group '{group}' already has permission '{permission}' disabled", "permission_already_disallowed": "Group '{group}' already has permission '{permission}' disabled",
@ -614,6 +660,7 @@
"service_disabled": "The service '{service}' will not be started anymore when system boots.", "service_disabled": "The service '{service}' will not be started anymore when system boots.",
"service_enable_failed": "Could not make the service '{service}' automatically start at boot.\n\nRecent service logs:{logs}", "service_enable_failed": "Could not make the service '{service}' automatically start at boot.\n\nRecent service logs:{logs}",
"service_enabled": "The service '{service}' will now be automatically started during system boots.", "service_enabled": "The service '{service}' will now be automatically started during system boots.",
"service_not_reloading_because_conf_broken": "Not reloading/restarting service '{name}' because its configuration is broken: {errors}",
"service_regen_conf_is_deprecated": "'yunohost service regen-conf' is deprecated! Please use 'yunohost tools regen-conf' instead.", "service_regen_conf_is_deprecated": "'yunohost service regen-conf' is deprecated! Please use 'yunohost tools regen-conf' instead.",
"service_reload_failed": "Could not reload the service '{service}'\n\nRecent service logs:{logs}", "service_reload_failed": "Could not reload the service '{service}'\n\nRecent service logs:{logs}",
"service_reload_or_restart_failed": "Could not reload or restart the service '{service}'\n\nRecent service logs:{logs}", "service_reload_or_restart_failed": "Could not reload or restart the service '{service}'\n\nRecent service logs:{logs}",
@ -677,4 +724,4 @@
"yunohost_installing": "Installing YunoHost...", "yunohost_installing": "Installing YunoHost...",
"yunohost_not_installed": "YunoHost is not correctly installed. Please run 'yunohost tools postinstall'", "yunohost_not_installed": "YunoHost is not correctly installed. Please run 'yunohost tools postinstall'",
"yunohost_postinstall_end_tip": "The post-install completed! To finalize your setup, please consider:\n - adding a first user through the 'Users' section of the webadmin (or 'yunohost user create <username>' in command-line);\n - diagnose potential issues through the 'Diagnosis' section of the webadmin (or 'yunohost diagnosis run' in command-line);\n - reading the 'Finalizing your setup' and 'Getting to know YunoHost' parts in the admin documentation: https://yunohost.org/admindoc." "yunohost_postinstall_end_tip": "The post-install completed! To finalize your setup, please consider:\n - adding a first user through the 'Users' section of the webadmin (or 'yunohost user create <username>' in command-line);\n - diagnose potential issues through the 'Diagnosis' section of the webadmin (or 'yunohost diagnosis run' in command-line);\n - reading the 'Finalizing your setup' and 'Getting to know YunoHost' parts in the admin documentation: https://yunohost.org/admindoc."
} }

View file

@ -28,9 +28,8 @@
"admin_password": "Pasvorto de la estro", "admin_password": "Pasvorto de la estro",
"admin_password_too_long": "Bonvolu elekti pasvorton pli mallonga ol 127 signoj", "admin_password_too_long": "Bonvolu elekti pasvorton pli mallonga ol 127 signoj",
"already_up_to_date": "Nenio por fari. Ĉio estas jam ĝisdatigita.", "already_up_to_date": "Nenio por fari. Ĉio estas jam ĝisdatigita.",
"app_argument_choice_invalid": "Uzu unu el ĉi tiuj elektoj '{choices}' por la argumento '{name}'", "app_argument_choice_invalid": "Uzu unu el ĉi tiuj elektoj '{choices}' por la argumento '{name}' anstataŭ '{value}'",
"app_argument_invalid": "Elektu validan valoron por la argumento '{name}': {error}", "app_argument_invalid": "Elektu validan valoron por la argumento '{name}': {error}",
"app_change_url_failed_nginx_reload": "Ne eblis reŝarĝi NGINX. Jen la eligo de 'nginx -t':\n{nginx_errors}",
"ask_new_admin_password": "Nova administrada pasvorto", "ask_new_admin_password": "Nova administrada pasvorto",
"app_action_broke_system": "Ĉi tiu ago ŝajne rompis ĉi tiujn gravajn servojn: {services}", "app_action_broke_system": "Ĉi tiu ago ŝajne rompis ĉi tiujn gravajn servojn: {services}",
"app_unsupported_remote_type": "Malkontrolita fora speco uzita por la apliko", "app_unsupported_remote_type": "Malkontrolita fora speco uzita por la apliko",
@ -121,7 +120,7 @@
"pattern_password": "Devas esti almenaŭ 3 signoj longaj", "pattern_password": "Devas esti almenaŭ 3 signoj longaj",
"root_password_desynchronized": "La pasvorta administranto estis ŝanĝita, sed YunoHost ne povis propagandi ĉi tion al la radika pasvorto!", "root_password_desynchronized": "La pasvorta administranto estis ŝanĝita, sed YunoHost ne povis propagandi ĉi tion al la radika pasvorto!",
"service_remove_failed": "Ne povis forigi la servon '{service}'", "service_remove_failed": "Ne povis forigi la servon '{service}'",
"backup_permission": "Rezerva permeso por app {app}", "backup_permission": "Rezerva permeso por {app}",
"log_user_group_delete": "Forigi grupon '{}'", "log_user_group_delete": "Forigi grupon '{}'",
"log_user_group_update": "Ĝisdatigi grupon '{}'", "log_user_group_update": "Ĝisdatigi grupon '{}'",
"dyndns_provider_unreachable": "Ne povas atingi la provizanton DynDNS {provider}: ĉu via YunoHost ne estas ĝuste konektita al la interreto aŭ la dyneta servilo malŝaltiĝas.", "dyndns_provider_unreachable": "Ne povas atingi la provizanton DynDNS {provider}: ĉu via YunoHost ne estas ĝuste konektita al la interreto aŭ la dyneta servilo malŝaltiĝas.",
@ -197,7 +196,6 @@
"certmanager_acme_not_configured_for_domain": "Atestilo por la domajno '{domain}' ne ŝajnas esti ĝuste instalita. Bonvolu ekzekuti 'cert-instali' por ĉi tiu regado unue.", "certmanager_acme_not_configured_for_domain": "Atestilo por la domajno '{domain}' ne ŝajnas esti ĝuste instalita. Bonvolu ekzekuti 'cert-instali' por ĉi tiu regado unue.",
"user_update_failed": "Ne povis ĝisdatigi uzanton {user}: {error}", "user_update_failed": "Ne povis ĝisdatigi uzanton {user}: {error}",
"restore_confirm_yunohost_installed": "Ĉu vi vere volas restarigi jam instalitan sistemon? [{answers}]", "restore_confirm_yunohost_installed": "Ĉu vi vere volas restarigi jam instalitan sistemon? [{answers}]",
"pattern_positive_number": "Devas esti pozitiva nombro",
"update_apt_cache_failed": "Ne eblis ĝisdatigi la kaŝmemoron de APT (paka administranto de Debian). Jen rubujo de la sources.list-linioj, kiuj povus helpi identigi problemajn liniojn:\n{sourceslist}", "update_apt_cache_failed": "Ne eblis ĝisdatigi la kaŝmemoron de APT (paka administranto de Debian). Jen rubujo de la sources.list-linioj, kiuj povus helpi identigi problemajn liniojn:\n{sourceslist}",
"migrations_no_migrations_to_run": "Neniuj migradoj por funkcii", "migrations_no_migrations_to_run": "Neniuj migradoj por funkcii",
"certmanager_attempt_to_renew_nonLE_cert": "La atestilo por la domajno '{domain}' ne estas elsendita de Let's Encrypt. Ne eblas renovigi ĝin aŭtomate!", "certmanager_attempt_to_renew_nonLE_cert": "La atestilo por la domajno '{domain}' ne estas elsendita de Let's Encrypt. Ne eblas renovigi ĝin aŭtomate!",
@ -252,7 +250,6 @@
"dyndns_unavailable": "La domajno '{domain}' ne haveblas.", "dyndns_unavailable": "La domajno '{domain}' ne haveblas.",
"experimental_feature": "Averto: Ĉi tiu funkcio estas eksperimenta kaj ne konsiderata stabila, vi ne uzu ĝin krom se vi scias kion vi faras.", "experimental_feature": "Averto: Ĉi tiu funkcio estas eksperimenta kaj ne konsiderata stabila, vi ne uzu ĝin krom se vi scias kion vi faras.",
"root_password_replaced_by_admin_password": "Via radika pasvorto estis anstataŭigita per via administra pasvorto.", "root_password_replaced_by_admin_password": "Via radika pasvorto estis anstataŭigita per via administra pasvorto.",
"domain_unknown": "Nekonata domajno",
"global_settings_setting_security_password_user_strength": "Uzanto pasvorta forto", "global_settings_setting_security_password_user_strength": "Uzanto pasvorta forto",
"restore_may_be_not_enough_disk_space": "Via sistemo ne ŝajnas havi sufiĉe da spaco (libera: {free_space} B, necesa spaco: {needed_space} B, sekureca marĝeno: {margin} B)", "restore_may_be_not_enough_disk_space": "Via sistemo ne ŝajnas havi sufiĉe da spaco (libera: {free_space} B, necesa spaco: {needed_space} B, sekureca marĝeno: {margin} B)",
"log_corrupted_md_file": "La YAD-metadata dosiero asociita kun protokoloj estas damaĝita: '{md_file}\nEraro: {error} '", "log_corrupted_md_file": "La YAD-metadata dosiero asociita kun protokoloj estas damaĝita: '{md_file}\nEraro: {error} '",
@ -326,7 +323,7 @@
"log_dyndns_subscribe": "Aboni al YunoHost-subdominio '{}'", "log_dyndns_subscribe": "Aboni al YunoHost-subdominio '{}'",
"password_too_simple_4": "La pasvorto bezonas almenaŭ 12 signojn kaj enhavas ciferon, majuskle, pli malaltan kaj specialajn signojn", "password_too_simple_4": "La pasvorto bezonas almenaŭ 12 signojn kaj enhavas ciferon, majuskle, pli malaltan kaj specialajn signojn",
"regenconf_file_updated": "Agordodosiero '{conf}' ĝisdatigita", "regenconf_file_updated": "Agordodosiero '{conf}' ĝisdatigita",
"log_help_to_get_log": "Por vidi la protokolon de la operacio '{desc}', uzu la komandon 'yunohost log show {name}{name}'", "log_help_to_get_log": "Por vidi la protokolon de la operacio '{desc}', uzu la komandon 'yunohost log show {name}'",
"global_settings_setting_security_nginx_compatibility": "Kongruo vs sekureca kompromiso por la TTT-servilo NGINX. Afektas la ĉifradojn (kaj aliajn aspektojn pri sekureco)", "global_settings_setting_security_nginx_compatibility": "Kongruo vs sekureca kompromiso por la TTT-servilo NGINX. Afektas la ĉifradojn (kaj aliajn aspektojn pri sekureco)",
"restore_complete": "Restarigita", "restore_complete": "Restarigita",
"hook_exec_failed": "Ne povis funkcii skripto: {path}", "hook_exec_failed": "Ne povis funkcii skripto: {path}",
@ -491,8 +488,6 @@
"diagnosis_description_ports": "Ekspoziciaj havenoj", "diagnosis_description_ports": "Ekspoziciaj havenoj",
"diagnosis_description_mail": "Retpoŝto", "diagnosis_description_mail": "Retpoŝto",
"log_app_action_run": "Funkciigu agon de la apliko '{}'", "log_app_action_run": "Funkciigu agon de la apliko '{}'",
"log_app_config_show_panel": "Montri la agordan panelon de la apliko '{}'",
"log_app_config_apply": "Apliki agordon al la apliko '{}'",
"diagnosis_never_ran_yet": "Ŝajnas, ke ĉi tiu servilo estis instalita antaŭ nelonge kaj estas neniu diagnoza raporto por montri. Vi devas komenci kurante plenan diagnozon, ĉu de la retadministro aŭ uzante 'yunohost diagnosis run' el la komandlinio.", "diagnosis_never_ran_yet": "Ŝajnas, ke ĉi tiu servilo estis instalita antaŭ nelonge kaj estas neniu diagnoza raporto por montri. Vi devas komenci kurante plenan diagnozon, ĉu de la retadministro aŭ uzante 'yunohost diagnosis run' el la komandlinio.",
"certmanager_warning_subdomain_dns_record": "Subdominio '{subdomain}' ne solvas al la sama IP-adreso kiel '{domain}'. Iuj funkcioj ne estos haveblaj ĝis vi riparos ĉi tion kaj regeneros la atestilon.", "certmanager_warning_subdomain_dns_record": "Subdominio '{subdomain}' ne solvas al la sama IP-adreso kiel '{domain}'. Iuj funkcioj ne estos haveblaj ĝis vi riparos ĉi tion kaj regeneros la atestilon.",
"diagnosis_basesystem_hardware": "Arkitekturo de servila aparataro estas {virt} {arch}", "diagnosis_basesystem_hardware": "Arkitekturo de servila aparataro estas {virt} {arch}",

View file

@ -53,7 +53,6 @@
"domain_dyndns_root_unknown": "Dominio raíz de DynDNS desconocido", "domain_dyndns_root_unknown": "Dominio raíz de DynDNS desconocido",
"domain_exists": "El dominio ya existe", "domain_exists": "El dominio ya existe",
"domain_uninstall_app_first": "Estas aplicaciones están todavía instaladas en tu dominio:\n{apps}\n\nPor favor desinstálalas utilizando <code>yunohost app remove the_app_id</code> o cambialas a otro dominio usando <code>yunohost app change-url the_app_id</code> antes de continuar con el borrado del dominio.", "domain_uninstall_app_first": "Estas aplicaciones están todavía instaladas en tu dominio:\n{apps}\n\nPor favor desinstálalas utilizando <code>yunohost app remove the_app_id</code> o cambialas a otro dominio usando <code>yunohost app change-url the_app_id</code> antes de continuar con el borrado del dominio.",
"domain_unknown": "Dominio desconocido",
"done": "Hecho.", "done": "Hecho.",
"downloading": "Descargando…", "downloading": "Descargando…",
"dyndns_ip_update_failed": "No se pudo actualizar la dirección IP en DynDNS", "dyndns_ip_update_failed": "No se pudo actualizar la dirección IP en DynDNS",
@ -91,7 +90,6 @@
"pattern_mailbox_quota": "Debe ser un tamaño con el sufijo «b/k/M/G/T» o «0» para no tener una cuota", "pattern_mailbox_quota": "Debe ser un tamaño con el sufijo «b/k/M/G/T» o «0» para no tener una cuota",
"pattern_password": "Debe contener al menos 3 caracteres", "pattern_password": "Debe contener al menos 3 caracteres",
"pattern_port_or_range": "Debe ser un número de puerto válido (es decir entre 0-65535) o un intervalo de puertos (por ejemplo 100:200)", "pattern_port_or_range": "Debe ser un número de puerto válido (es decir entre 0-65535) o un intervalo de puertos (por ejemplo 100:200)",
"pattern_positive_number": "Deber ser un número positivo",
"pattern_username": "Solo puede contener caracteres alfanuméricos o el guión bajo", "pattern_username": "Solo puede contener caracteres alfanuméricos o el guión bajo",
"port_already_closed": "El puerto {port} ya está cerrado para las conexiones {ip_version}", "port_already_closed": "El puerto {port} ya está cerrado para las conexiones {ip_version}",
"port_already_opened": "El puerto {port} ya está abierto para las conexiones {ip_version}", "port_already_opened": "El puerto {port} ya está abierto para las conexiones {ip_version}",
@ -171,7 +169,6 @@
"certmanager_acme_not_configured_for_domain": "El reto ACME no ha podido ser realizado para {domain} porque su configuración de nginx no tiene el el código correcto... Por favor, asegurate que la configuración de nginx es correcta ejecutando en el terminal `yunohost tools regen-conf nginx --dry-run --with-diff`.", "certmanager_acme_not_configured_for_domain": "El reto ACME no ha podido ser realizado para {domain} porque su configuración de nginx no tiene el el código correcto... Por favor, asegurate que la configuración de nginx es correcta ejecutando en el terminal `yunohost tools regen-conf nginx --dry-run --with-diff`.",
"domain_hostname_failed": "No se pudo establecer un nuevo nombre de anfitrión («hostname»). Esto podría causar problemas más tarde (no es seguro... podría ir bien).", "domain_hostname_failed": "No se pudo establecer un nuevo nombre de anfitrión («hostname»). Esto podría causar problemas más tarde (no es seguro... podría ir bien).",
"app_already_installed_cant_change_url": "Esta aplicación ya está instalada. La URL no se puede cambiar solo con esta función. Marque `app changeurl` si está disponible.", "app_already_installed_cant_change_url": "Esta aplicación ya está instalada. La URL no se puede cambiar solo con esta función. Marque `app changeurl` si está disponible.",
"app_change_url_failed_nginx_reload": "No se pudo recargar NGINX. Esta es la salida de «nginx -t»:\n{nginx_errors}",
"app_change_url_identical_domains": "El antiguo y nuevo dominio/url_path son idénticos ('{domain} {path}'), no se realizarán cambios.", "app_change_url_identical_domains": "El antiguo y nuevo dominio/url_path son idénticos ('{domain} {path}'), no se realizarán cambios.",
"app_change_url_no_script": "La aplicación «{app_name}» aún no permite la modificación de URLs. Quizás debería actualizarla.", "app_change_url_no_script": "La aplicación «{app_name}» aún no permite la modificación de URLs. Quizás debería actualizarla.",
"app_change_url_success": "El URL de la aplicación {app} es ahora {domain} {path}", "app_change_url_success": "El URL de la aplicación {app} es ahora {domain} {path}",
@ -325,7 +322,7 @@
"log_does_exists": "No existe ningún registro de actividades con el nombre '{log}', ejecute 'yunohost log list' para ver todos los registros de actividades disponibles", "log_does_exists": "No existe ningún registro de actividades con el nombre '{log}', ejecute 'yunohost log list' para ver todos los registros de actividades disponibles",
"log_help_to_get_failed_log": "No se pudo completar la operación «{desc}». Para obtener ayuda, comparta el registro completo de esta operación ejecutando la orden «yunohost log share {name}»", "log_help_to_get_failed_log": "No se pudo completar la operación «{desc}». Para obtener ayuda, comparta el registro completo de esta operación ejecutando la orden «yunohost log share {name}»",
"log_link_to_failed_log": "No se pudo completar la operación «{desc}». Para obtener ayuda, proporcione el registro completo de esta operación <a href=\"#/tools/logs/{name}\">pulsando aquí</a>", "log_link_to_failed_log": "No se pudo completar la operación «{desc}». Para obtener ayuda, proporcione el registro completo de esta operación <a href=\"#/tools/logs/{name}\">pulsando aquí</a>",
"log_help_to_get_log": "Para ver el registro de la operación «{desc}», ejecute la orden «yunohost log show {name}{name}»", "log_help_to_get_log": "Para ver el registro de la operación «{desc}», ejecute la orden «yunohost log show {name}»",
"log_link_to_log": "Registro completo de esta operación: «<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>»", "log_link_to_log": "Registro completo de esta operación: «<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>»",
"log_corrupted_md_file": "El archivo de metadatos YAML asociado con el registro está dañado: «{md_file}\nError: {error}»", "log_corrupted_md_file": "El archivo de metadatos YAML asociado con el registro está dañado: «{md_file}\nError: {error}»",
"hook_json_return_error": "No se pudo leer la respuesta del gancho {path}. Error: {msg}. Contenido sin procesar: {raw_content}", "hook_json_return_error": "No se pudo leer la respuesta del gancho {path}. Error: {msg}. Contenido sin procesar: {raw_content}",
@ -480,8 +477,6 @@
"diagnosis_description_web": "Web", "diagnosis_description_web": "Web",
"diagnosis_basesystem_hardware": "La arquitectura material del servidor es {virt} {arch}", "diagnosis_basesystem_hardware": "La arquitectura material del servidor es {virt} {arch}",
"log_domain_main_domain": "Hacer de '{}' el dominio principal", "log_domain_main_domain": "Hacer de '{}' el dominio principal",
"log_app_config_apply": "Aplica la configuración de la aplicación '{}'",
"log_app_config_show_panel": "Muestra el panel de configuración de la aplicación '{}'",
"log_app_action_run": "Inicializa la acción de la aplicación '{}'", "log_app_action_run": "Inicializa la acción de la aplicación '{}'",
"group_already_exist_on_system_but_removing_it": "El grupo {group} ya existe en los grupos del sistema, pero YunoHost lo suprimirá …", "group_already_exist_on_system_but_removing_it": "El grupo {group} ya existe en los grupos del sistema, pero YunoHost lo suprimirá …",
"global_settings_setting_pop3_enabled": "Habilita el protocolo POP3 para el servidor de correo electrónico", "global_settings_setting_pop3_enabled": "Habilita el protocolo POP3 para el servidor de correo electrónico",

View file

@ -1,7 +1,6 @@
{ {
"action_invalid": "اقدام نامعتبر '{action}'", "action_invalid": "اقدام نامعتبر '{action}'",
"aborting": "رها کردن.", "aborting": "رها کردن.",
"app_change_url_failed_nginx_reload": "NGINX بارگیری نشد. در اینجا خروجی 'nginx -t' است:\n{nginx_errors}",
"app_argument_required": "استدلال '{name}' الزامی است", "app_argument_required": "استدلال '{name}' الزامی است",
"app_argument_password_no_default": "خطا هنگام تجزیه گذرواژه '{name}': به دلایل امنیتی استدلال رمز عبور نمی تواند مقدار پیش فرض داشته باشد", "app_argument_password_no_default": "خطا هنگام تجزیه گذرواژه '{name}': به دلایل امنیتی استدلال رمز عبور نمی تواند مقدار پیش فرض داشته باشد",
"app_argument_invalid": "یک مقدار معتبر انتخاب کنید برای استدلال '{name}':{error}", "app_argument_invalid": "یک مقدار معتبر انتخاب کنید برای استدلال '{name}':{error}",
@ -152,7 +151,7 @@
"apps_catalog_update_success": "کاتالوگ برنامه به روز شد!", "apps_catalog_update_success": "کاتالوگ برنامه به روز شد!",
"apps_catalog_obsolete_cache": "حافظه پنهان کاتالوگ برنامه خالی یا منسوخ شده است.", "apps_catalog_obsolete_cache": "حافظه پنهان کاتالوگ برنامه خالی یا منسوخ شده است.",
"apps_catalog_failed_to_download": "بارگیری کاتالوگ برنامه {apps_catalog} امکان پذیر نیست: {error}", "apps_catalog_failed_to_download": "بارگیری کاتالوگ برنامه {apps_catalog} امکان پذیر نیست: {error}",
"apps_catalog_updating": "در حال به روز رسانی کاتالوگ برنامه", "apps_catalog_updating": "در حال به روز رسانی کاتالوگ برنامه...",
"apps_catalog_init_success": "سیستم کاتالوگ برنامه راه اندازی اولیه شد!", "apps_catalog_init_success": "سیستم کاتالوگ برنامه راه اندازی اولیه شد!",
"apps_already_up_to_date": "همه برنامه ها در حال حاضر به روز هستند", "apps_already_up_to_date": "همه برنامه ها در حال حاضر به روز هستند",
"app_packaging_format_not_supported": "این برنامه قابل نصب نیست زیرا قالب بسته بندی آن توسط نسخه YunoHost شما پشتیبانی نمی شود. احتمالاً باید ارتقاء سیستم خود را در نظر بگیرید.", "app_packaging_format_not_supported": "این برنامه قابل نصب نیست زیرا قالب بسته بندی آن توسط نسخه YunoHost شما پشتیبانی نمی شود. احتمالاً باید ارتقاء سیستم خود را در نظر بگیرید.",
@ -352,10 +351,9 @@
"dyndns_could_not_check_provide": "بررسی نشد که آیا {provider} می تواند {domain} را ارائه دهد یا خیر.", "dyndns_could_not_check_provide": "بررسی نشد که آیا {provider} می تواند {domain} را ارائه دهد یا خیر.",
"dpkg_lock_not_available": "این دستور در حال حاضر قابل اجرا نیست زیرا به نظر می رسد برنامه دیگری از قفل dpkg (مدیر بسته سیستم) استفاده می کند", "dpkg_lock_not_available": "این دستور در حال حاضر قابل اجرا نیست زیرا به نظر می رسد برنامه دیگری از قفل dpkg (مدیر بسته سیستم) استفاده می کند",
"dpkg_is_broken": "شما نمی توانید این کار را در حال حاضر انجام دهید زیرا dpkg/APT (اداره کنندگان سیستم بسته ها) به نظر می رسد در وضعیت خرابی است… می توانید با اتصال از طریق SSH و اجرا این فرمان `sudo apt install --fix-broken` and/or `sudo dpkg --configure -a` مشکل را حل کنید.", "dpkg_is_broken": "شما نمی توانید این کار را در حال حاضر انجام دهید زیرا dpkg/APT (اداره کنندگان سیستم بسته ها) به نظر می رسد در وضعیت خرابی است… می توانید با اتصال از طریق SSH و اجرا این فرمان `sudo apt install --fix-broken` and/or `sudo dpkg --configure -a` مشکل را حل کنید.",
"downloading": "در حال بارگیری", "downloading": "در حال بارگیری...",
"done": "انجام شد", "done": "انجام شد",
"domains_available": "دامنه های موجود:", "domains_available": "دامنه های موجود:",
"domain_unknown": "دامنه ناشناخته",
"domain_name_unknown": "دامنه '{domain}' ناشناخته است", "domain_name_unknown": "دامنه '{domain}' ناشناخته است",
"domain_uninstall_app_first": "این برنامه ها هنوز روی دامنه شما نصب هستند:\n{apps}\n\nلطفاً قبل از اقدام به حذف دامنه ، آنها را با استفاده از 'برنامه yunohost remove the_app_id' حذف کرده یا با استفاده از 'yunohost app change-url the_app_id' به دامنه دیگری منتقل کنید", "domain_uninstall_app_first": "این برنامه ها هنوز روی دامنه شما نصب هستند:\n{apps}\n\nلطفاً قبل از اقدام به حذف دامنه ، آنها را با استفاده از 'برنامه yunohost remove the_app_id' حذف کرده یا با استفاده از 'yunohost app change-url the_app_id' به دامنه دیگری منتقل کنید",
"domain_remove_confirm_apps_removal": "حذف این دامنه برنامه های زیر را حذف می کند:\n{apps}\n\nآیا طمئن هستید که میخواهید انجام دهید؟ [{answers}]", "domain_remove_confirm_apps_removal": "حذف این دامنه برنامه های زیر را حذف می کند:\n{apps}\n\nآیا طمئن هستید که میخواهید انجام دهید؟ [{answers}]",
@ -378,7 +376,6 @@
"permission_already_allowed": "گروه '{group}' قبلاً مجوز '{permission}' را فعال کرده است", "permission_already_allowed": "گروه '{group}' قبلاً مجوز '{permission}' را فعال کرده است",
"pattern_password_app": "متأسفیم ، گذرواژه ها نمی توانند شامل کاراکترهای زیر باشند: {forbidden_chars}", "pattern_password_app": "متأسفیم ، گذرواژه ها نمی توانند شامل کاراکترهای زیر باشند: {forbidden_chars}",
"pattern_username": "باید فقط حروف الفبایی کوچک و خط زیر باشد", "pattern_username": "باید فقط حروف الفبایی کوچک و خط زیر باشد",
"pattern_positive_number": "باید یک عدد مثبت باشد",
"pattern_port_or_range": "باید یک شماره پورت معتبر (یعنی 0-65535) یا محدوده پورت (به عنوان مثال 100: 200) باشد", "pattern_port_or_range": "باید یک شماره پورت معتبر (یعنی 0-65535) یا محدوده پورت (به عنوان مثال 100: 200) باشد",
"pattern_password": "باید حداقل 3 کاراکتر داشته باشد", "pattern_password": "باید حداقل 3 کاراکتر داشته باشد",
"pattern_mailbox_quota": "باید اندازه ای با پسوند b / k / M / G / T یا 0 داشته باشد تا سهمیه نداشته باشد", "pattern_mailbox_quota": "باید اندازه ای با پسوند b / k / M / G / T یا 0 داشته باشد تا سهمیه نداشته باشد",
@ -488,8 +485,6 @@
"log_backup_restore_system": "بازیابی سیستم بوسیله آرشیو پشتیبان", "log_backup_restore_system": "بازیابی سیستم بوسیله آرشیو پشتیبان",
"log_backup_create": "بایگانی پشتیبان ایجاد کنید", "log_backup_create": "بایگانی پشتیبان ایجاد کنید",
"log_available_on_yunopaste": "این گزارش اکنون از طریق {url} در دسترس است", "log_available_on_yunopaste": "این گزارش اکنون از طریق {url} در دسترس است",
"log_app_config_apply": "پیکربندی را در برنامه '{}' اعمال کنید",
"log_app_config_show_panel": "پانل پیکربندی برنامه '{}' را نشان دهید",
"log_app_action_run": "عملکرد برنامه '{}' را اجرا کنید", "log_app_action_run": "عملکرد برنامه '{}' را اجرا کنید",
"log_app_makedefault": "\"{}\" را برنامه پیش فرض قرار دهید", "log_app_makedefault": "\"{}\" را برنامه پیش فرض قرار دهید",
"log_app_upgrade": "برنامه '{}' را ارتقاء دهید", "log_app_upgrade": "برنامه '{}' را ارتقاء دهید",
@ -500,7 +495,7 @@
"log_does_exists": "هیچ گزارش عملیاتی با نام '{log}' وجود ندارد ، برای مشاهده همه گزارش عملیّات های موجود در خط فرمان از دستور 'yunohost log list' استفاده کنید", "log_does_exists": "هیچ گزارش عملیاتی با نام '{log}' وجود ندارد ، برای مشاهده همه گزارش عملیّات های موجود در خط فرمان از دستور 'yunohost log list' استفاده کنید",
"log_help_to_get_failed_log": "عملیات '{desc}' کامل نشد. لطفاً برای دریافت راهنمایی و کمک ، گزارش کامل این عملیات را با استفاده از دستور 'yunohost log share {name}' به اشتراک بگذارید", "log_help_to_get_failed_log": "عملیات '{desc}' کامل نشد. لطفاً برای دریافت راهنمایی و کمک ، گزارش کامل این عملیات را با استفاده از دستور 'yunohost log share {name}' به اشتراک بگذارید",
"log_link_to_failed_log": "عملیّات '{desc}' کامل نشد. لطفاً گزارش کامل این عملیات را ارائه دهید بواسطه <a href=\"#/tools/logs/{name}\">اینجا را کلیک کنید</a> برای دریافت کمک", "log_link_to_failed_log": "عملیّات '{desc}' کامل نشد. لطفاً گزارش کامل این عملیات را ارائه دهید بواسطه <a href=\"#/tools/logs/{name}\">اینجا را کلیک کنید</a> برای دریافت کمک",
"log_help_to_get_log": "برای مشاهده گزارش عملیات '{desc}'، از دستور 'yunohost log show {name}{name}' استفاده کنید", "log_help_to_get_log": "برای مشاهده گزارش عملیات '{desc}'، از دستور 'yunohost log show {name}' استفاده کنید",
"log_link_to_log": "گزارش کامل این عملیات: <a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>'", "log_link_to_log": "گزارش کامل این عملیات: <a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>'",
"log_corrupted_md_file": "فایل فوق داده YAML مربوط به گزارش ها آسیب دیده است: '{md_file}\nخطا: {error} '", "log_corrupted_md_file": "فایل فوق داده YAML مربوط به گزارش ها آسیب دیده است: '{md_file}\nخطا: {error} '",
"ldap_server_is_down_restart_it": "سرویس LDAP خاموش است ، سعی کنید آن را دوباره راه اندازی کنید...", "ldap_server_is_down_restart_it": "سرویس LDAP خاموش است ، سعی کنید آن را دوباره راه اندازی کنید...",
@ -538,11 +533,11 @@
"unbackup_app": "{app} ذخیره نمی شود", "unbackup_app": "{app} ذخیره نمی شود",
"tools_upgrade_special_packages_completed": "ارتقاء بسته YunoHost به پایان رسید\nبرای بازگرداندن خط فرمان [Enter] را فشار دهید", "tools_upgrade_special_packages_completed": "ارتقاء بسته YunoHost به پایان رسید\nبرای بازگرداندن خط فرمان [Enter] را فشار دهید",
"tools_upgrade_special_packages_explanation": "ارتقاء ویژه در پس زمینه ادامه خواهد یافت. لطفاً تا 10 دقیقه دیگر (بسته به سرعت سخت افزار) هیچ اقدام دیگری را روی سرور خود شروع نکنید. پس از این کار ، ممکن است مجبور شوید دوباره وارد webadmin شوید. گزارش ارتقاء در Tools → Log (در webadmin) یا با استفاده از 'yunohost log list' (در خط فرمان) در دسترس خواهد بود.", "tools_upgrade_special_packages_explanation": "ارتقاء ویژه در پس زمینه ادامه خواهد یافت. لطفاً تا 10 دقیقه دیگر (بسته به سرعت سخت افزار) هیچ اقدام دیگری را روی سرور خود شروع نکنید. پس از این کار ، ممکن است مجبور شوید دوباره وارد webadmin شوید. گزارش ارتقاء در Tools → Log (در webadmin) یا با استفاده از 'yunohost log list' (در خط فرمان) در دسترس خواهد بود.",
"tools_upgrade_special_packages": "در حال ارتقاء بسته های 'special' (مربوط به yunohost)", "tools_upgrade_special_packages": "در حال ارتقاء بسته های 'special' (مربوط به yunohost)...",
"tools_upgrade_regular_packages_failed": "بسته ها را نمی توان ارتقا داد: {packages_list}", "tools_upgrade_regular_packages_failed": "بسته ها را نمی توان ارتقا داد: {packages_list}",
"tools_upgrade_regular_packages": "در حال ارتقاء بسته های 'regular' (غیر مرتبط با yunohost)", "tools_upgrade_regular_packages": "در حال ارتقاء بسته های 'regular' (غیر مرتبط با yunohost)...",
"tools_upgrade_cant_unhold_critical_packages": "بسته های مهم و حیاتی را نمی توان نگه نداشت", "tools_upgrade_cant_unhold_critical_packages": "بسته های مهم و حیاتی را نمی توان نگه نداشت...",
"tools_upgrade_cant_hold_critical_packages": "بسته های مهم و حیاتی را نمی توان نگه داشت", "tools_upgrade_cant_hold_critical_packages": "بسته های مهم و حیاتی را نمی توان نگه داشت...",
"tools_upgrade_cant_both": "نمی توان سیستم و برنامه ها را به طور همزمان ارتقا داد", "tools_upgrade_cant_both": "نمی توان سیستم و برنامه ها را به طور همزمان ارتقا داد",
"tools_upgrade_at_least_one": "لطفاً مشخص کنید 'apps' ، یا 'system'", "tools_upgrade_at_least_one": "لطفاً مشخص کنید 'apps' ، یا 'system'",
"this_action_broke_dpkg": "این اقدام dpkg/APT (مدیران بسته های سیستم) را خراب کرد... می توانید با اتصال از طریق SSH و اجرای فرمان `sudo apt install --fix -break` و/یا` sudo dpkg --configure -a` این مشکل را حل کنید.", "this_action_broke_dpkg": "این اقدام dpkg/APT (مدیران بسته های سیستم) را خراب کرد... می توانید با اتصال از طریق SSH و اجرای فرمان `sudo apt install --fix -break` و/یا` sudo dpkg --configure -a` این مشکل را حل کنید.",
@ -597,15 +592,15 @@
"root_password_replaced_by_admin_password": "گذرواژه ریشه شما با رمز مدیریت جایگزین شده است.", "root_password_replaced_by_admin_password": "گذرواژه ریشه شما با رمز مدیریت جایگزین شده است.",
"root_password_desynchronized": "گذرواژه مدیریت تغییر کرد ، اما YunoHost نتوانست این را به رمز عبور ریشه منتقل کند!", "root_password_desynchronized": "گذرواژه مدیریت تغییر کرد ، اما YunoHost نتوانست این را به رمز عبور ریشه منتقل کند!",
"restore_system_part_failed": "بخش سیستم '{part}' بازیابی و ترمیم نشد", "restore_system_part_failed": "بخش سیستم '{part}' بازیابی و ترمیم نشد",
"restore_running_hooks": "در حال اجرای قلاب های ترمیم و بازیابی", "restore_running_hooks": "در حال اجرای قلاب های ترمیم و بازیابی...",
"restore_running_app_script": "ترمیم و بازیابی برنامه '{app}'", "restore_running_app_script": "ترمیم و بازیابی برنامه '{app}'...",
"restore_removing_tmp_dir_failed": "پوشه موقت قدیمی حذف نشد", "restore_removing_tmp_dir_failed": "پوشه موقت قدیمی حذف نشد",
"restore_nothings_done": "هیچ چیز ترمیم و بازسازی نشد", "restore_nothings_done": "هیچ چیز ترمیم و بازسازی نشد",
"restore_not_enough_disk_space": "فضای کافی موجود نیست (فضا: {free_space} B ، فضای مورد نیاز: {needed_space} B ، حاشیه امنیتی: {margin} B)", "restore_not_enough_disk_space": "فضای کافی موجود نیست (فضا: {free_space} B ، فضای مورد نیاز: {needed_space} B ، حاشیه امنیتی: {margin} B)",
"restore_may_be_not_enough_disk_space": "به نظر می رسد سیستم شما فضای کافی ندارد (فضای آزاد: {free_space} B ، فضای مورد نیاز: {needed_space} B ، حاشیه امنیتی: {margin} B)", "restore_may_be_not_enough_disk_space": "به نظر می رسد سیستم شما فضای کافی ندارد (فضای آزاد: {free_space} B ، فضای مورد نیاز: {needed_space} B ، حاشیه امنیتی: {margin} B)",
"restore_hook_unavailable": "اسکریپت ترمیم و بازسازی برای '{part}' در سیستم شما در دسترس نیست و همچنین در بایگانی نیز وجود ندارد", "restore_hook_unavailable": "اسکریپت ترمیم و بازسازی برای '{part}' در سیستم شما در دسترس نیست و همچنین در بایگانی نیز وجود ندارد",
"restore_failed": "سیستم بازیابی نشد", "restore_failed": "سیستم بازیابی نشد",
"restore_extracting": "استخراج فایل های مورد نیاز از بایگانی", "restore_extracting": "استخراج فایل های مورد نیاز از بایگانی...",
"restore_confirm_yunohost_installed": "آیا واقعاً می خواهید سیستمی که هم اکنون نصب شده را بازیابی کنید؟ [{answers}]", "restore_confirm_yunohost_installed": "آیا واقعاً می خواهید سیستمی که هم اکنون نصب شده را بازیابی کنید؟ [{answers}]",
"restore_complete": "مرمت به پایان رسید", "restore_complete": "مرمت به پایان رسید",
"restore_cleaning_failed": "فهرست بازسازی موقت پاک نشد", "restore_cleaning_failed": "فهرست بازسازی موقت پاک نشد",
@ -617,7 +612,7 @@
"regenconf_need_to_explicitly_specify_ssh": "پیکربندی ssh به صورت دستی تغییر یافته است ، اما شما باید صراحتاً دسته \"ssh\" را با --force برای اعمال تغییرات در واقع مشخص کنید.", "regenconf_need_to_explicitly_specify_ssh": "پیکربندی ssh به صورت دستی تغییر یافته است ، اما شما باید صراحتاً دسته \"ssh\" را با --force برای اعمال تغییرات در واقع مشخص کنید.",
"regenconf_pending_applying": "در حال اعمال پیکربندی معلق برای دسته '{category}'...", "regenconf_pending_applying": "در حال اعمال پیکربندی معلق برای دسته '{category}'...",
"regenconf_failed": "پیکربندی برای دسته (ها) بازسازی نشد: {categories}", "regenconf_failed": "پیکربندی برای دسته (ها) بازسازی نشد: {categories}",
"regenconf_dry_pending_applying": "در حال بررسی پیکربندی معلق که برای دسته '{category}' اعمال می شد", "regenconf_dry_pending_applying": "در حال بررسی پیکربندی معلق که برای دسته '{category}' اعمال می شد...",
"regenconf_would_be_updated": "پیکربندی برای دسته '{category}' به روز می شد", "regenconf_would_be_updated": "پیکربندی برای دسته '{category}' به روز می شد",
"regenconf_updated": "پیکربندی برای دسته '{category}' به روز شد", "regenconf_updated": "پیکربندی برای دسته '{category}' به روز شد",
"regenconf_up_to_date": "پیکربندی در حال حاضر برای دسته '{category}' به روز است", "regenconf_up_to_date": "پیکربندی در حال حاضر برای دسته '{category}' به روز است",
@ -642,4 +637,4 @@
"permission_deleted": "مجوز '{permission}' حذف شد", "permission_deleted": "مجوز '{permission}' حذف شد",
"permission_cant_add_to_all_users": "مجوز {permission} را نمی توان به همه کاربران اضافه کرد.", "permission_cant_add_to_all_users": "مجوز {permission} را نمی توان به همه کاربران اضافه کرد.",
"permission_currently_allowed_for_all_users": "این مجوز در حال حاضر به همه کاربران علاوه بر آن گروه های دیگر نیز اعطا شده. احتمالاً بخواهید مجوز 'all_users' را حذف کنید یا سایر گروه هایی را که در حال حاضر مجوز به آنها اعطا شده است را هم حذف کنید." "permission_currently_allowed_for_all_users": "این مجوز در حال حاضر به همه کاربران علاوه بر آن گروه های دیگر نیز اعطا شده. احتمالاً بخواهید مجوز 'all_users' را حذف کنید یا سایر گروه هایی را که در حال حاضر مجوز به آنها اعطا شده است را هم حذف کنید."
} }

View file

@ -4,7 +4,7 @@
"admin_password_change_failed": "Impossible de changer le mot de passe", "admin_password_change_failed": "Impossible de changer le mot de passe",
"admin_password_changed": "Le mot de passe d'administration a été modifié", "admin_password_changed": "Le mot de passe d'administration a été modifié",
"app_already_installed": "{app} est déjà installé", "app_already_installed": "{app} est déjà installé",
"app_argument_choice_invalid": "Choix invalide pour le paramètre '{name}', il doit être l'un de {choices}", "app_argument_choice_invalid": "Choix invalide pour le paramètre '{name}'. Les valeurs acceptées sont {choices}, au lieu de '{value}'",
"app_argument_invalid": "Valeur invalide pour le paramètre '{name}' : {error}", "app_argument_invalid": "Valeur invalide pour le paramètre '{name}' : {error}",
"app_argument_required": "Le paramètre '{name}' est requis", "app_argument_required": "Le paramètre '{name}' est requis",
"app_extraction_failed": "Impossible d'extraire les fichiers d'installation", "app_extraction_failed": "Impossible d'extraire les fichiers d'installation",
@ -42,7 +42,7 @@
"backup_output_directory_forbidden": "Choisissez un répertoire de destination différent. Les sauvegardes ne peuvent pas être créées dans les sous-dossiers /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ou /home/yunohost.backup/archives", "backup_output_directory_forbidden": "Choisissez un répertoire de destination différent. Les sauvegardes ne peuvent pas être créées dans les sous-dossiers /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ou /home/yunohost.backup/archives",
"backup_output_directory_not_empty": "Le répertoire de destination n'est pas vide", "backup_output_directory_not_empty": "Le répertoire de destination n'est pas vide",
"backup_output_directory_required": "Vous devez spécifier un dossier de destination pour la sauvegarde", "backup_output_directory_required": "Vous devez spécifier un dossier de destination pour la sauvegarde",
"backup_running_hooks": "Exécution des scripts de sauvegarde...", "backup_running_hooks": "Exécution des scripts de sauvegarde ...",
"custom_app_url_required": "Vous devez spécifier une URL pour mettre à jour votre application personnalisée {app}", "custom_app_url_required": "Vous devez spécifier une URL pour mettre à jour votre application personnalisée {app}",
"disk_space_not_sufficient_install": "Il ne reste pas assez d'espace disque pour installer cette application", "disk_space_not_sufficient_install": "Il ne reste pas assez d'espace disque pour installer cette application",
"disk_space_not_sufficient_update": "Il ne reste pas assez d'espace disque pour mettre à jour cette application", "disk_space_not_sufficient_update": "Il ne reste pas assez d'espace disque pour mettre à jour cette application",
@ -55,7 +55,6 @@
"domain_dyndns_root_unknown": "Domaine DynDNS principal inconnu", "domain_dyndns_root_unknown": "Domaine DynDNS principal inconnu",
"domain_exists": "Le domaine existe déjà", "domain_exists": "Le domaine existe déjà",
"domain_uninstall_app_first": "Ces applications sont toujours installées sur votre domaine :\n{apps}\n\nVeuillez les désinstaller avec la commande 'yunohost app remove nom-de-l-application' ou les déplacer vers un autre domaine avec la commande 'yunohost app change-url nom-de-l-application' avant de procéder à la suppression du domaine", "domain_uninstall_app_first": "Ces applications sont toujours installées sur votre domaine :\n{apps}\n\nVeuillez les désinstaller avec la commande 'yunohost app remove nom-de-l-application' ou les déplacer vers un autre domaine avec la commande 'yunohost app change-url nom-de-l-application' avant de procéder à la suppression du domaine",
"domain_unknown": "Domaine inconnu",
"done": "Terminé", "done": "Terminé",
"downloading": "Téléchargement en cours...", "downloading": "Téléchargement en cours...",
"dyndns_ip_update_failed": "Impossible de mettre à jour l'adresse IP sur le domaine DynDNS", "dyndns_ip_update_failed": "Impossible de mettre à jour l'adresse IP sur le domaine DynDNS",
@ -93,7 +92,6 @@
"pattern_mailbox_quota": "Doit avoir une taille suffixée avec b/k/M/G/T ou 0 pour désactiver le quota", "pattern_mailbox_quota": "Doit avoir une taille suffixée avec b/k/M/G/T ou 0 pour désactiver le quota",
"pattern_password": "Doit être composé d'au moins 3 caractères", "pattern_password": "Doit être composé d'au moins 3 caractères",
"pattern_port_or_range": "Doit être un numéro de port valide compris entre 0 et 65535, ou une gamme de ports (exemple : 100:200)", "pattern_port_or_range": "Doit être un numéro de port valide compris entre 0 et 65535, ou une gamme de ports (exemple : 100:200)",
"pattern_positive_number": "Doit être un nombre positif",
"pattern_username": "Doit être composé uniquement de caractères alphanumériques minuscules et de tirets bas (aussi appelé tiret du 8 ou underscore)", "pattern_username": "Doit être composé uniquement de caractères alphanumériques minuscules et de tirets bas (aussi appelé tiret du 8 ou underscore)",
"port_already_closed": "Le port {port} est déjà fermé pour les connexions {ip_version}", "port_already_closed": "Le port {port} est déjà fermé pour les connexions {ip_version}",
"port_already_opened": "Le port {port} est déjà ouvert pour les connexions {ip_version}", "port_already_opened": "Le port {port} est déjà ouvert pour les connexions {ip_version}",
@ -137,15 +135,15 @@
"upnp_dev_not_found": "Aucun périphérique compatible UPnP n'a été trouvé", "upnp_dev_not_found": "Aucun périphérique compatible UPnP n'a été trouvé",
"upnp_disabled": "L'UPnP est désactivé", "upnp_disabled": "L'UPnP est désactivé",
"upnp_enabled": "L'UPnP est activé", "upnp_enabled": "L'UPnP est activé",
"upnp_port_open_failed": "Impossible douvrir les ports UPnP", "upnp_port_open_failed": "Impossible d'ouvrir les ports UPnP",
"user_created": "Lutilisateur a été créé", "user_created": "L'utilisateur a été créé",
"user_creation_failed": "Impossible de créer lutilisateur {user} : {error}", "user_creation_failed": "Impossible de créer l'utilisateur {user} : {error}",
"user_deleted": "Lutilisateur a été supprimé", "user_deleted": "L'utilisateur a été supprimé",
"user_deletion_failed": "Impossible de supprimer lutilisateur {user} : {error}", "user_deletion_failed": "Impossible de supprimer l'utilisateur {user} : {error}",
"user_home_creation_failed": "Impossible de créer le dossier personnel '{home}' de lutilisateur", "user_home_creation_failed": "Impossible de créer le dossier personnel '{home}' de l'utilisateur",
"user_unknown": "Lutilisateur {user} est inconnu", "user_unknown": "L'utilisateur {user} est inconnu",
"user_update_failed": "Impossible de mettre à jour lutilisateur {user} : {error}", "user_update_failed": "Impossible de mettre à jour l'utilisateur {user} : {error}",
"user_updated": "Lutilisateur a été modifié", "user_updated": "L'utilisateur a été modifié",
"yunohost_already_installed": "YunoHost est déjà installé", "yunohost_already_installed": "YunoHost est déjà installé",
"yunohost_configured": "YunoHost est maintenant configuré", "yunohost_configured": "YunoHost est maintenant configuré",
"yunohost_installing": "L'installation de YunoHost est en cours...", "yunohost_installing": "L'installation de YunoHost est en cours...",
@ -169,11 +167,10 @@
"certmanager_unable_to_parse_self_CA_name": "Impossible d'analyser le nom de l'autorité du certificat auto-signé (fichier : {file})", "certmanager_unable_to_parse_self_CA_name": "Impossible d'analyser le nom de l'autorité du certificat auto-signé (fichier : {file})",
"mailbox_used_space_dovecot_down": "Le service Dovecot doit être démarré si vous souhaitez voir l'espace disque occupé par la messagerie", "mailbox_used_space_dovecot_down": "Le service Dovecot doit être démarré si vous souhaitez voir l'espace disque occupé par la messagerie",
"domains_available": "Domaines disponibles :", "domains_available": "Domaines disponibles :",
"backup_archive_broken_link": "Impossible daccéder à larchive de sauvegarde (lien invalide vers {path})", "backup_archive_broken_link": "Impossible d'accéder à l'archive de sauvegarde (lien invalide vers {path})",
"certmanager_acme_not_configured_for_domain": "Le challenge ACME n'a pas pu être validé pour le domaine {domain} pour le moment car le code de la configuration NGINX est manquant... Merci de vérifier que votre configuration NGINX est à jour avec la commande : `yunohost tools regen-conf nginx --dry-run --with-diff`.", "certmanager_acme_not_configured_for_domain": "Le challenge ACME n'a pas pu être validé pour le domaine {domain} pour le moment car le code de la configuration NGINX est manquant... Merci de vérifier que votre configuration NGINX est à jour avec la commande : `yunohost tools regen-conf nginx --dry-run --with-diff`.",
"domain_hostname_failed": "Échec de lutilisation dun nouveau nom d'hôte. Cela pourrait causer des soucis plus tard (cela n'en causera peut-être pas).", "domain_hostname_failed": "Échec de l'utilisation d'un nouveau nom d'hôte. Cela pourrait causer des soucis plus tard (cela n'en causera peut-être pas).",
"app_already_installed_cant_change_url": "Cette application est déjà installée. LURL ne peut pas être changé simplement par cette fonction. Vérifiez si cela est disponible avec `app changeurl`.", "app_already_installed_cant_change_url": "Cette application est déjà installée. L'URL ne peut pas être changé simplement par cette fonction. Vérifiez si cela est disponible avec `app changeurl`.",
"app_change_url_failed_nginx_reload": "Le redémarrage de NGINX a échoué. Voici la sortie de 'nginx -t' :\n{nginx_errors}",
"app_change_url_identical_domains": "L'ancien et le nouveau couple domaine/chemin_de_l'URL sont identiques pour ('{domain}{path}'), rien à faire.", "app_change_url_identical_domains": "L'ancien et le nouveau couple domaine/chemin_de_l'URL sont identiques pour ('{domain}{path}'), rien à faire.",
"app_change_url_no_script": "L'application '{app_name}' ne prend pas encore en charge le changement d'URL. Vous devriez peut-être la mettre à jour.", "app_change_url_no_script": "L'application '{app_name}' ne prend pas encore en charge le changement d'URL. Vous devriez peut-être la mettre à jour.",
"app_change_url_success": "L'URL de l'application {app} a été changée en {domain}{path}", "app_change_url_success": "L'URL de l'application {app} a été changée en {domain}{path}",
@ -188,9 +185,9 @@
"global_settings_unknown_type": "Situation inattendue : la configuration {setting} semble avoir le type {unknown_type} mais celui-ci n'est pas pris en charge par le système.", "global_settings_unknown_type": "Situation inattendue : la configuration {setting} semble avoir le type {unknown_type} mais celui-ci n'est pas pris en charge par le système.",
"global_settings_unknown_setting_from_settings_file": "Clé inconnue dans les paramètres : '{setting_key}', rejet de cette clé et sauvegarde de celle-ci dans /etc/yunohost/unkown_settings.json", "global_settings_unknown_setting_from_settings_file": "Clé inconnue dans les paramètres : '{setting_key}', rejet de cette clé et sauvegarde de celle-ci dans /etc/yunohost/unkown_settings.json",
"backup_abstract_method": "Cette méthode de sauvegarde reste à implémenter", "backup_abstract_method": "Cette méthode de sauvegarde reste à implémenter",
"backup_applying_method_tar": "Création de l'archive TAR de la sauvegarde...", "backup_applying_method_tar": "Création de l'archive TAR de la sauvegarde ...",
"backup_applying_method_copy": "Copie de tous les fichiers à sauvegarder...", "backup_applying_method_copy": "Copie de tous les fichiers à sauvegarder ...",
"backup_applying_method_custom": "Appel de la méthode de sauvegarde personnalisée '{method}'...", "backup_applying_method_custom": "Appel de la méthode de sauvegarde personnalisée '{method}' ...",
"backup_archive_system_part_not_available": "La partie '{part}' du système n'est pas disponible dans cette sauvegarde", "backup_archive_system_part_not_available": "La partie '{part}' du système n'est pas disponible dans cette sauvegarde",
"backup_archive_writing_error": "Impossible d'ajouter des fichiers '{source}' (nommés dans l'archive : '{dest}') à sauvegarder dans l'archive compressée '{archive}'", "backup_archive_writing_error": "Impossible d'ajouter des fichiers '{source}' (nommés dans l'archive : '{dest}') à sauvegarder dans l'archive compressée '{archive}'",
"backup_ask_for_copying_if_needed": "Voulez-vous effectuer la sauvegarde en utilisant {size}Mo temporairement ? (Cette méthode est utilisée car certains fichiers n'ont pas pu être préparés avec une méthode plus efficace.)", "backup_ask_for_copying_if_needed": "Voulez-vous effectuer la sauvegarde en utilisant {size}Mo temporairement ? (Cette méthode est utilisée car certains fichiers n'ont pas pu être préparés avec une méthode plus efficace.)",
@ -251,7 +248,7 @@
"experimental_feature": "Attention : cette fonctionnalité est expérimentale et ne doit pas être considérée comme stable, vous ne devriez pas l'utiliser à moins que vous ne sachiez ce que vous faites.", "experimental_feature": "Attention : cette fonctionnalité est expérimentale et ne doit pas être considérée comme stable, vous ne devriez pas l'utiliser à moins que vous ne sachiez ce que vous faites.",
"log_corrupted_md_file": "Le fichier YAML de métadonnées associé aux logs est corrompu : '{md_file}'\nErreur : {error}", "log_corrupted_md_file": "Le fichier YAML de métadonnées associé aux logs est corrompu : '{md_file}'\nErreur : {error}",
"log_link_to_log": "Journal complet de cette opération : '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\"> {desc} </a>'", "log_link_to_log": "Journal complet de cette opération : '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\"> {desc} </a>'",
"log_help_to_get_log": "Pour voir le journal de cette opération '{desc}', utilisez la commande 'yunohost log show {name}{name}'", "log_help_to_get_log": "Pour voir le journal de cette opération '{desc}', utilisez la commande 'yunohost log show {name}'",
"log_link_to_failed_log": "L'opération '{desc}' a échoué ! Pour obtenir de l'aide, merci de partager le journal de l'opération en <a href=\"#/tools/logs/{name}\">cliquant ici</a>", "log_link_to_failed_log": "L'opération '{desc}' a échoué ! Pour obtenir de l'aide, merci de partager le journal de l'opération en <a href=\"#/tools/logs/{name}\">cliquant ici</a>",
"log_help_to_get_failed_log": "L'opération '{desc}' a échoué ! Pour obtenir de l'aide, merci de partager le journal de l'opération en utilisant la commande 'yunohost log share {name}'", "log_help_to_get_failed_log": "L'opération '{desc}' a échoué ! Pour obtenir de l'aide, merci de partager le journal de l'opération en utilisant la commande 'yunohost log share {name}'",
"log_does_exists": "Il n'y a pas de journal des opérations avec le nom '{log}', utilisez 'yunohost log list' pour voir tous les journaux d'opérations disponibles", "log_does_exists": "Il n'y a pas de journal des opérations avec le nom '{log}', utilisez 'yunohost log list' pour voir tous les journaux d'opérations disponibles",
@ -300,7 +297,7 @@
"app_upgrade_several_apps": "Les applications suivantes seront mises à jour : {apps}", "app_upgrade_several_apps": "Les applications suivantes seront mises à jour : {apps}",
"ask_new_domain": "Nouveau domaine", "ask_new_domain": "Nouveau domaine",
"ask_new_path": "Nouveau chemin", "ask_new_path": "Nouveau chemin",
"backup_actually_backuping": "Création d'une archive de sauvegarde à partir des fichiers collectés...", "backup_actually_backuping": "Création d'une archive de sauvegarde à partir des fichiers collectés ...",
"backup_mount_archive_for_restore": "Préparation de l'archive pour restauration...", "backup_mount_archive_for_restore": "Préparation de l'archive pour restauration...",
"confirm_app_install_warning": "Avertissement : cette application peut fonctionner mais n'est pas bien intégrée dans YunoHost. Certaines fonctionnalités telles que l'authentification unique et la sauvegarde/restauration peuvent ne pas être disponibles. L'installer quand même ? [{answers}] ", "confirm_app_install_warning": "Avertissement : cette application peut fonctionner mais n'est pas bien intégrée dans YunoHost. Certaines fonctionnalités telles que l'authentification unique et la sauvegarde/restauration peuvent ne pas être disponibles. L'installer quand même ? [{answers}] ",
"confirm_app_install_danger": "DANGER ! Cette application est connue pour être encore expérimentale (si elle ne fonctionne pas explicitement) ! Vous ne devriez probablement PAS l'installer à moins de savoir ce que vous faites. AUCUN SUPPORT ne sera fourni si cette application ne fonctionne pas ou casse votre système... Si vous êtes prêt à prendre ce risque de toute façon, tapez '{answers}'", "confirm_app_install_danger": "DANGER ! Cette application est connue pour être encore expérimentale (si elle ne fonctionne pas explicitement) ! Vous ne devriez probablement PAS l'installer à moins de savoir ce que vous faites. AUCUN SUPPORT ne sera fourni si cette application ne fonctionne pas ou casse votre système... Si vous êtes prêt à prendre ce risque de toute façon, tapez '{answers}'",
@ -494,8 +491,6 @@
"diagnosis_http_timeout": "Expiration du délai en essayant de contacter votre serveur de l'extérieur. Il semble être inaccessible. Vérifiez que vous transférez correctement le port 80, que Nginx est en cours d'exécution et qu'un pare-feu n'interfère pas.", "diagnosis_http_timeout": "Expiration du délai en essayant de contacter votre serveur de l'extérieur. Il semble être inaccessible. Vérifiez que vous transférez correctement le port 80, que Nginx est en cours d'exécution et qu'un pare-feu n'interfère pas.",
"global_settings_setting_pop3_enabled": "Activer le protocole POP3 pour le serveur de messagerie", "global_settings_setting_pop3_enabled": "Activer le protocole POP3 pour le serveur de messagerie",
"log_app_action_run": "Lancer l'action de l'application '{}'", "log_app_action_run": "Lancer l'action de l'application '{}'",
"log_app_config_show_panel": "Montrer le panneau de configuration de l'application '{}'",
"log_app_config_apply": "Appliquer la configuration à l'application '{}'",
"diagnosis_never_ran_yet": "Il apparaît que le serveur a été installé récemment et qu'il n'y a pas encore eu de diagnostic. Vous devriez en lancer un depuis la webadmin ou en utilisant 'yunohost diagnosis run' depuis la ligne de commande.", "diagnosis_never_ran_yet": "Il apparaît que le serveur a été installé récemment et qu'il n'y a pas encore eu de diagnostic. Vous devriez en lancer un depuis la webadmin ou en utilisant 'yunohost diagnosis run' depuis la ligne de commande.",
"diagnosis_description_web": "Web", "diagnosis_description_web": "Web",
"diagnosis_basesystem_hardware": "L'architecture du serveur est {virt} {arch}", "diagnosis_basesystem_hardware": "L'architecture du serveur est {virt} {arch}",
@ -528,7 +523,7 @@
"diagnosis_mail_ehlo_ok": "Le serveur de messagerie SMTP est accessible de l'extérieur et peut donc recevoir des emails !", "diagnosis_mail_ehlo_ok": "Le serveur de messagerie SMTP est accessible de l'extérieur et peut donc recevoir des emails !",
"diagnosis_mail_ehlo_unreachable": "Le serveur de messagerie SMTP est inaccessible de l'extérieur en IPv{ipversion}. Il ne pourra pas recevoir des emails.", "diagnosis_mail_ehlo_unreachable": "Le serveur de messagerie SMTP est inaccessible de l'extérieur en IPv{ipversion}. Il ne pourra pas recevoir des emails.",
"diagnosis_mail_ehlo_unreachable_details": "Impossible d'ouvrir une connexion sur le port 25 à votre serveur en IPv{ipversion}. Il semble inaccessible. <br> 1. La cause la plus courante de ce problème est que le port 25 <a href='https://yunohost.org/isp_box_config'>n'est pas correctement redirigé vers votre serveur</a>. <br> 2. Vous devez également vous assurer que le service postfix est en cours d'exécution. <br> 3. Sur les configurations plus complexes: assurez-vous qu'aucun pare-feu ou proxy inversé n'interfère.", "diagnosis_mail_ehlo_unreachable_details": "Impossible d'ouvrir une connexion sur le port 25 à votre serveur en IPv{ipversion}. Il semble inaccessible. <br> 1. La cause la plus courante de ce problème est que le port 25 <a href='https://yunohost.org/isp_box_config'>n'est pas correctement redirigé vers votre serveur</a>. <br> 2. Vous devez également vous assurer que le service postfix est en cours d'exécution. <br> 3. Sur les configurations plus complexes: assurez-vous qu'aucun pare-feu ou proxy inversé n'interfère.",
"diagnosis_mail_ehlo_wrong_details": "Le EHLO reçu par le serveur de diagnostique distant en IPv{ipversion} est différent du domaine de votre serveur. <br> EHLO reçu: <code>{wrong_ehlo}</code> <br> Attendu : <code>{right_ehlo}</code> <br> La cause la plus courante ce problème est que le port 25 <a href='https://yunohost.org/isp_box_config'> n'est pas correctement redirigé vers votre serveur </a>. Vous pouvez également vous assurer qu'aucun pare-feu ou proxy inversé n'interfère.", "diagnosis_mail_ehlo_wrong_details": "Le EHLO reçu par le serveur de diagnostique distant en IPv{ipversion} est différent du domaine de votre serveur.<br>EHLO reçu : <code>{wrong_ehlo}</code><br>Attendu : <code>{right_ehlo}</code><br>La cause la plus courante à ce problème est que le port 25 <a href='https ://yunohost.org/isp_box_config'>n'est pas correctement redirigé vers votre serveur</a>. Vous pouvez également vous assurer qu'aucun pare-feu ou reverse-proxy n'interfère.",
"diagnosis_mail_fcrdns_nok_alternatives_4": "Certains fournisseurs ne vous laisseront pas configurer votre DNS inversé (ou leur fonctionnalité pourrait être cassée...). Si vous rencontrez des problèmes à cause de cela, envisagez les solutions suivantes : <br> - Certains FAI fournissent l'alternative de <a href='https://yunohost.org/#/email_configure_relay'>à l'aide d'un relais de serveur de messagerie</a> bien que cela implique que le relais pourra espionner votre trafic de messagerie. <br> - Une alternative respectueuse de la vie privée consiste à utiliser un VPN *avec une IP publique dédiée* pour contourner ce type de limites. Voir <a href='https://yunohost.org/#/vpn_advantage'>https://yunohost.org/#/vpn_advantage</a> <br> - Enfin, il est également possible de <a href='https://yunohost.org/#/isp'>changer de fournisseur</a>", "diagnosis_mail_fcrdns_nok_alternatives_4": "Certains fournisseurs ne vous laisseront pas configurer votre DNS inversé (ou leur fonctionnalité pourrait être cassée...). Si vous rencontrez des problèmes à cause de cela, envisagez les solutions suivantes : <br> - Certains FAI fournissent l'alternative de <a href='https://yunohost.org/#/email_configure_relay'>à l'aide d'un relais de serveur de messagerie</a> bien que cela implique que le relais pourra espionner votre trafic de messagerie. <br> - Une alternative respectueuse de la vie privée consiste à utiliser un VPN *avec une IP publique dédiée* pour contourner ce type de limites. Voir <a href='https://yunohost.org/#/vpn_advantage'>https://yunohost.org/#/vpn_advantage</a> <br> - Enfin, il est également possible de <a href='https://yunohost.org/#/isp'>changer de fournisseur</a>",
"diagnosis_mail_fcrdns_nok_alternatives_6": "Certains fournisseurs ne vous laisseront pas configurer votre DNS inversé (ou leur fonctionnalité pourrait être cassée...). Si votre DNS inversé est correctement configuré en IPv4, vous pouvez essayer de désactiver l'utilisation d'IPv6 lors de l'envoi d'emails en exécutant <cmd>yunohost settings set smtp.allow_ipv6 -v off</cmd>. Remarque : cette dernière solution signifie que vous ne pourrez pas envoyer ou recevoir de emails avec les quelques serveurs qui ont uniquement de l'IPv6.", "diagnosis_mail_fcrdns_nok_alternatives_6": "Certains fournisseurs ne vous laisseront pas configurer votre DNS inversé (ou leur fonctionnalité pourrait être cassée...). Si votre DNS inversé est correctement configuré en IPv4, vous pouvez essayer de désactiver l'utilisation d'IPv6 lors de l'envoi d'emails en exécutant <cmd>yunohost settings set smtp.allow_ipv6 -v off</cmd>. Remarque : cette dernière solution signifie que vous ne pourrez pas envoyer ou recevoir de emails avec les quelques serveurs qui ont uniquement de l'IPv6.",
"diagnosis_mail_fcrdns_different_from_ehlo_domain_details": "DNS inverse actuel : <code>{rdns_domain}</code> <br> Valeur attendue : <code>{ehlo_domain}</code>", "diagnosis_mail_fcrdns_different_from_ehlo_domain_details": "DNS inverse actuel : <code>{rdns_domain}</code> <br> Valeur attendue : <code>{ehlo_domain}</code>",
@ -657,5 +652,28 @@
"user_import_missing_columns": "Les colonnes suivantes sont manquantes : {columns}", "user_import_missing_columns": "Les colonnes suivantes sont manquantes : {columns}",
"user_import_bad_file": "Votre fichier CSV n'est pas correctement formaté, il sera ignoré afin d'éviter une potentielle perte de données", "user_import_bad_file": "Votre fichier CSV n'est pas correctement formaté, il sera ignoré afin d'éviter une potentielle perte de données",
"user_import_bad_line": "Ligne incorrecte {line} : {details}", "user_import_bad_line": "Ligne incorrecte {line} : {details}",
"log_user_import": "Importer des utilisateurs" "log_user_import": "Importer des utilisateurs",
} "diagnosis_high_number_auth_failures": "Il y a eu récemment un grand nombre d'échecs d'authentification. Assurez-vous que Fail2Ban est en cours d'exécution et est correctement configuré, ou utilisez un port personnalisé pour SSH comme expliqué dans https://yunohost.org/security.",
"global_settings_setting_security_nginx_redirect_to_https": "Rediriger les requêtes HTTP vers HTTPS par défaut (NE PAS DÉSACTIVER à moins de savoir vraiment ce que vous faites !)",
"config_validate_color": "Doit être une couleur hexadécimale RVB valide",
"app_config_unable_to_apply": "Échec de l'application des valeurs du panneau de configuration.",
"app_config_unable_to_read": "Échec de la lecture des valeurs du panneau de configuration.",
"config_apply_failed": "Échec de l'application de la nouvelle configuration : {error}",
"config_cant_set_value_on_section": "Vous ne pouvez pas définir une seule valeur sur une section de configuration entière.",
"config_forbidden_keyword": "Le mot-clé '{keyword}' est réservé, vous ne pouvez pas créer ou utiliser un panneau de configuration avec une question avec cet identifiant.",
"config_no_panel": "Aucun panneau de configuration trouvé.",
"config_unknown_filter_key": "La clé de filtre '{filter_key}' est incorrecte.",
"config_validate_date": "Doit être une date valide comme dans le format AAAA-MM-JJ",
"config_validate_email": "Doit être un email valide",
"config_validate_time": "Doit être une heure valide comme HH:MM",
"config_validate_url": "Doit être une URL Web valide",
"config_version_not_supported": "Les versions du panneau de configuration '{version}' ne sont pas prises en charge.",
"danger": "Danger :",
"file_extension_not_accepted": "Le fichier '{path}' est refusé car son extension ne fait pas partie des extensions acceptées : {accept}",
"invalid_number_min": "Doit être supérieur à {min}",
"invalid_number_max": "Doit être inférieur à {max}",
"log_app_config_set": "Appliquer la configuration à l'application '{}'",
"service_not_reloading_because_conf_broken": "Le service '{name}' n'a pas été rechargé/redémarré car sa configuration est cassée : {errors}",
"app_argument_password_help_keep": "Tapez sur Entrée pour conserver la valeur actuelle",
"app_argument_password_help_optional": "Tapez un espace pour vider le mot de passe"
}

View file

@ -14,11 +14,10 @@
"additional_urls_already_removed": "URL adicional '{url}' xa foi eliminada das URL adicionais para o permiso '{permission}'", "additional_urls_already_removed": "URL adicional '{url}' xa foi eliminada das URL adicionais para o permiso '{permission}'",
"additional_urls_already_added": "URL adicional '{url}' xa fora engadida ás URL adicionais para o permiso '{permission}'", "additional_urls_already_added": "URL adicional '{url}' xa fora engadida ás URL adicionais para o permiso '{permission}'",
"action_invalid": "Acción non válida '{action}'", "action_invalid": "Acción non válida '{action}'",
"app_change_url_failed_nginx_reload": "Non se recargou NGINX. Aquí tes a saída de 'nginx -t':\n{nginx_errors}",
"app_argument_required": "Requírese o argumento '{name}'", "app_argument_required": "Requírese o argumento '{name}'",
"app_argument_password_no_default": "Erro ao procesar o argumento do contrasinal '{name}': o argumento do contrasinal non pode ter un valor por defecto por razón de seguridade", "app_argument_password_no_default": "Erro ao procesar o argumento do contrasinal '{name}': o argumento do contrasinal non pode ter un valor por defecto por razón de seguridade",
"app_argument_invalid": "Elixe un valor válido para o argumento '{name}': {error}", "app_argument_invalid": "Elixe un valor válido para o argumento '{name}': {error}",
"app_argument_choice_invalid": "Usa unha destas opcións '{choices}' para o argumento '{name}'", "app_argument_choice_invalid": "Usa unha destas opcións '{choices}' para o argumento '{name}' no lugar de '{value}'",
"backup_archive_writing_error": "Non se puideron engadir os ficheiros '{source}' (chamados no arquivo '{dest}' para ser copiados dentro do arquivo comprimido '{archive}'", "backup_archive_writing_error": "Non se puideron engadir os ficheiros '{source}' (chamados no arquivo '{dest}' para ser copiados dentro do arquivo comprimido '{archive}'",
"backup_archive_system_part_not_available": "A parte do sistema '{part}' non está dispoñible nesta copia", "backup_archive_system_part_not_available": "A parte do sistema '{part}' non está dispoñible nesta copia",
"backup_archive_corrupted": "Semella que o arquivo de copia '{archive}' está estragado : {error}", "backup_archive_corrupted": "Semella que o arquivo de copia '{archive}' está estragado : {error}",
@ -45,7 +44,7 @@
"apps_catalog_update_success": "O catálogo de aplicacións foi actualizado!", "apps_catalog_update_success": "O catálogo de aplicacións foi actualizado!",
"apps_catalog_obsolete_cache": "A caché do catálogo de apps está baleiro ou obsoleto.", "apps_catalog_obsolete_cache": "A caché do catálogo de apps está baleiro ou obsoleto.",
"apps_catalog_failed_to_download": "Non se puido descargar o catálogo de apps {apps_catalog}: {error}", "apps_catalog_failed_to_download": "Non se puido descargar o catálogo de apps {apps_catalog}: {error}",
"apps_catalog_updating": "Actualizando o catálogo de aplicacións", "apps_catalog_updating": "Actualizando o catálogo de aplicacións...",
"apps_catalog_init_success": "Sistema do catálogo de apps iniciado!", "apps_catalog_init_success": "Sistema do catálogo de apps iniciado!",
"apps_already_up_to_date": "Xa tes tódalas apps ao día", "apps_already_up_to_date": "Xa tes tódalas apps ao día",
"app_packaging_format_not_supported": "Esta app non se pode instalar porque o formato de empaquetado non está soportado pola túa versión de YunoHost. Deberías considerar actualizar o teu sistema.", "app_packaging_format_not_supported": "Esta app non se pode instalar porque o formato de empaquetado non está soportado pola túa versión de YunoHost. Deberías considerar actualizar o teu sistema.",
@ -292,10 +291,9 @@
"dyndns_could_not_check_provide": "Non se comprobou se {provider} pode proporcionar {domain}.", "dyndns_could_not_check_provide": "Non se comprobou se {provider} pode proporcionar {domain}.",
"dpkg_lock_not_available": "Non se pode executar agora mesmo este comando porque semella que outro programa está a utilizar dpkg (o xestos de paquetes do sistema)", "dpkg_lock_not_available": "Non se pode executar agora mesmo este comando porque semella que outro programa está a utilizar dpkg (o xestos de paquetes do sistema)",
"dpkg_is_broken": "Non podes facer isto agora mesmo porque dpkg/APT (o xestor de paquetes do sistema) semella que non está a funcionar... Podes intentar solucionalo conectándote a través de SSH e executando `sudo apt install --fix-broken`e/ou `sudo dpkg --configure -a`.", "dpkg_is_broken": "Non podes facer isto agora mesmo porque dpkg/APT (o xestor de paquetes do sistema) semella que non está a funcionar... Podes intentar solucionalo conectándote a través de SSH e executando `sudo apt install --fix-broken`e/ou `sudo dpkg --configure -a`.",
"downloading": "Descargando", "downloading": "Descargando...",
"done": "Feito", "done": "Feito",
"domains_available": "Dominios dispoñibles:", "domains_available": "Dominios dispoñibles:",
"domain_unknown": "Dominio descoñecido",
"domain_name_unknown": "Dominio '{domain}' descoñecido", "domain_name_unknown": "Dominio '{domain}' descoñecido",
"domain_uninstall_app_first": "Aínda están instaladas estas aplicacións no teu dominio:\n{apps}\n\nPrimeiro desinstalaas utilizando 'yunohost app remove id_da_app' ou móveas a outro dominio con 'yunohost app change-url id_da_app' antes de eliminar o dominio", "domain_uninstall_app_first": "Aínda están instaladas estas aplicacións no teu dominio:\n{apps}\n\nPrimeiro desinstalaas utilizando 'yunohost app remove id_da_app' ou móveas a outro dominio con 'yunohost app change-url id_da_app' antes de eliminar o dominio",
"domain_remove_confirm_apps_removal": "Ao eliminar o dominio tamén vas eliminar estas aplicacións:\n{apps}\n\nTes a certeza de querer facelo? [{answers}]", "domain_remove_confirm_apps_removal": "Ao eliminar o dominio tamén vas eliminar estas aplicacións:\n{apps}\n\nTes a certeza de querer facelo? [{answers}]",
@ -358,7 +356,7 @@
"global_settings_setting_security_webadmin_allowlist_enabled": "Permitir que só algúns IPs accedan á webadmin.", "global_settings_setting_security_webadmin_allowlist_enabled": "Permitir que só algúns IPs accedan á webadmin.",
"disk_space_not_sufficient_update": "Non hai espazo suficiente no disco para actualizar esta aplicación", "disk_space_not_sufficient_update": "Non hai espazo suficiente no disco para actualizar esta aplicación",
"disk_space_not_sufficient_install": "Non queda espazo suficiente no disco para instalar esta aplicación", "disk_space_not_sufficient_install": "Non queda espazo suficiente no disco para instalar esta aplicación",
"log_help_to_get_log": "Para ver o rexistro completo da operación '{desc}', usa o comando 'yunohost log show {name}{name}'", "log_help_to_get_log": "Para ver o rexistro completo da operación '{desc}', usa o comando 'yunohost log show {name}'",
"log_link_to_log": "Rexistro completo desta operación: '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>'", "log_link_to_log": "Rexistro completo desta operación: '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>'",
"log_corrupted_md_file": "O ficheiro YAML con metadatos asociado aos rexistros está danado: '{md_file}\nErro: {error}'", "log_corrupted_md_file": "O ficheiro YAML con metadatos asociado aos rexistros está danado: '{md_file}\nErro: {error}'",
"iptables_unavailable": "Non podes andar remexendo en iptables aquí. Ou ben estás nun contedor ou o teu kernel non ten soporte para isto", "iptables_unavailable": "Non podes andar remexendo en iptables aquí. Ou ben estás nun contedor ou o teu kernel non ten soporte para isto",
@ -386,8 +384,6 @@
"log_backup_restore_system": "Restablecer o sistema desde unha copia de apoio", "log_backup_restore_system": "Restablecer o sistema desde unha copia de apoio",
"log_backup_create": "Crear copia de apoio", "log_backup_create": "Crear copia de apoio",
"log_available_on_yunopaste": "Este rexistro está dispoñible en {url}", "log_available_on_yunopaste": "Este rexistro está dispoñible en {url}",
"log_app_config_apply": "Aplicar a configuración da app '{}'",
"log_app_config_show_panel": "Mostrar o panel de configuración da app '{}'",
"log_app_action_run": "Executar acción da app '{}'", "log_app_action_run": "Executar acción da app '{}'",
"log_app_makedefault": "Converter '{}' na app por defecto", "log_app_makedefault": "Converter '{}' na app por defecto",
"log_app_upgrade": "Actualizar a app '{}'", "log_app_upgrade": "Actualizar a app '{}'",
@ -458,7 +454,7 @@
"migration_0015_specific_upgrade": "Iniciando a actualización dos paquetes do sistema que precisan ser actualizados de xeito independente...", "migration_0015_specific_upgrade": "Iniciando a actualización dos paquetes do sistema que precisan ser actualizados de xeito independente...",
"migration_0015_modified_files": "Ten en conta que os seguintes ficheiros semella que foron modificados manualmente e poderían ser sobrescritos na actualización: {manually_modified_files}", "migration_0015_modified_files": "Ten en conta que os seguintes ficheiros semella que foron modificados manualmente e poderían ser sobrescritos na actualización: {manually_modified_files}",
"migration_0015_problematic_apps_warning": "Ten en conta que se detectaron as seguintes apps que poderían ser problemáticas. Semella que non foron instaladas usando o catálogo de YunoHost, ou non están marcadas como 'funcionais'. En consecuencia, non se pode garantir que seguirán funcionando após a actualización: {problematic_apps}", "migration_0015_problematic_apps_warning": "Ten en conta que se detectaron as seguintes apps que poderían ser problemáticas. Semella que non foron instaladas usando o catálogo de YunoHost, ou non están marcadas como 'funcionais'. En consecuencia, non se pode garantir que seguirán funcionando após a actualización: {problematic_apps}",
"diagnosis_http_localdomain": "O dominio {domain}, cun TLD .local, non é de agardar que sexa accesible desde o exterior da rede local.", "diagnosis_http_localdomain": "O dominio {domain}, cun TLD .local, non é de agardar que esté exposto ao exterior da rede local.",
"diagnosis_dns_specialusedomain": "O dominio {domain} baséase un dominio de nivel alto e uso especial (TLD) polo que non é de agardar que realmente teña rexistros DNS.", "diagnosis_dns_specialusedomain": "O dominio {domain} baséase un dominio de nivel alto e uso especial (TLD) polo que non é de agardar que realmente teña rexistros DNS.",
"upnp_enabled": "UPnP activado", "upnp_enabled": "UPnP activado",
"upnp_disabled": "UPnP desactivado", "upnp_disabled": "UPnP desactivado",
@ -471,7 +467,6 @@
"permission_already_allowed": "O grupo '{group}' xa ten o permiso '{permission}' activado", "permission_already_allowed": "O grupo '{group}' xa ten o permiso '{permission}' activado",
"pattern_password_app": "Lamentámolo, os contrasinais non poden conter os seguintes caracteres: {forbidden_chars}", "pattern_password_app": "Lamentámolo, os contrasinais non poden conter os seguintes caracteres: {forbidden_chars}",
"pattern_username": "Só admite caracteres alfanuméricos en minúscula e trazo baixo", "pattern_username": "Só admite caracteres alfanuméricos en minúscula e trazo baixo",
"pattern_positive_number": "Ten que ser un número positivo",
"pattern_port_or_range": "Debe ser un número válido de porto (entre 0-65535) ou rango de portos (ex. 100:200)", "pattern_port_or_range": "Debe ser un número válido de porto (entre 0-65535) ou rango de portos (ex. 100:200)",
"pattern_password": "Ten que ter polo menos 3 caracteres", "pattern_password": "Ten que ter polo menos 3 caracteres",
"pattern_mailbox_quota": "Ten que ser un tamaño co sufixo b/k/M/G/T ou 0 para non ter unha cota", "pattern_mailbox_quota": "Ten que ser un tamaño co sufixo b/k/M/G/T ou 0 para non ter unha cota",
@ -524,7 +519,7 @@
"permission_cant_add_to_all_users": "O permiso {permission} non pode ser concecido a tódalas usuarias.", "permission_cant_add_to_all_users": "O permiso {permission} non pode ser concecido a tódalas usuarias.",
"permission_currently_allowed_for_all_users": "Este permiso está concedido actualmente a tódalas usuarias ademáis de a outros grupos. Probablemente queiras ben eliminar o permiso 'all_users' ou ben eliminar os outros grupos que teñen permiso.", "permission_currently_allowed_for_all_users": "Este permiso está concedido actualmente a tódalas usuarias ademáis de a outros grupos. Probablemente queiras ben eliminar o permiso 'all_users' ou ben eliminar os outros grupos que teñen permiso.",
"restore_failed": "Non se puido restablecer o sistema", "restore_failed": "Non se puido restablecer o sistema",
"restore_extracting": "Extraendo os ficheiros necesarios desde o arquivo", "restore_extracting": "Extraendo os ficheiros necesarios desde o arquivo...",
"restore_confirm_yunohost_installed": "Tes a certeza de querer restablecer un sistema xa instalado? [{answers}]", "restore_confirm_yunohost_installed": "Tes a certeza de querer restablecer un sistema xa instalado? [{answers}]",
"restore_complete": "Restablecemento completado", "restore_complete": "Restablecemento completado",
"restore_cleaning_failed": "Non se puido despexar o directorio temporal de restablecemento", "restore_cleaning_failed": "Non se puido despexar o directorio temporal de restablecemento",
@ -536,7 +531,7 @@
"regenconf_need_to_explicitly_specify_ssh": "A configuración ssh foi modificada manualmente, pero tes que indicar explícitamente a categoría 'ssh' con --force para realmente aplicar os cambios.", "regenconf_need_to_explicitly_specify_ssh": "A configuración ssh foi modificada manualmente, pero tes que indicar explícitamente a categoría 'ssh' con --force para realmente aplicar os cambios.",
"regenconf_pending_applying": "Aplicando a configuración pendente para categoría '{category}'...", "regenconf_pending_applying": "Aplicando a configuración pendente para categoría '{category}'...",
"regenconf_failed": "Non se rexenerou a configuración para a categoría(s): {categories}", "regenconf_failed": "Non se rexenerou a configuración para a categoría(s): {categories}",
"regenconf_dry_pending_applying": "Comprobando as configuracións pendentes que deberían aplicarse á categoría '{category}'", "regenconf_dry_pending_applying": "Comprobando as configuracións pendentes que deberían aplicarse á categoría '{category}'...",
"regenconf_would_be_updated": "A configuración debería ser actualizada para a categoría '{category}'", "regenconf_would_be_updated": "A configuración debería ser actualizada para a categoría '{category}'",
"regenconf_updated": "Configuración actualizada para '{category}'", "regenconf_updated": "Configuración actualizada para '{category}'",
"regenconf_up_to_date": "A configuración xa está ao día para a categoría '{category}'", "regenconf_up_to_date": "A configuración xa está ao día para a categoría '{category}'",
@ -574,8 +569,8 @@
"root_password_replaced_by_admin_password": "O contrasinal root foi substituído polo teu contrasinal de administración.", "root_password_replaced_by_admin_password": "O contrasinal root foi substituído polo teu contrasinal de administración.",
"root_password_desynchronized": "Mudou o contrasinal de administración, pero YunoHost non puido transferir este cambio ao contrasinal root!", "root_password_desynchronized": "Mudou o contrasinal de administración, pero YunoHost non puido transferir este cambio ao contrasinal root!",
"restore_system_part_failed": "Non se restableceu a parte do sistema '{part}'", "restore_system_part_failed": "Non se restableceu a parte do sistema '{part}'",
"restore_running_hooks": "Executando os ganchos do restablecemento", "restore_running_hooks": "Executando os ganchos do restablecemento...",
"restore_running_app_script": "Restablecendo a app '{app}'", "restore_running_app_script": "Restablecendo a app '{app}'...",
"restore_removing_tmp_dir_failed": "Non se puido eliminar o directorio temporal antigo", "restore_removing_tmp_dir_failed": "Non se puido eliminar o directorio temporal antigo",
"restore_nothings_done": "Nada foi restablecido", "restore_nothings_done": "Nada foi restablecido",
"restore_not_enough_disk_space": "Non hai espazo abondo (espazo: {free_space.d} B, espazo necesario: {needed_space} B, marxe de seguridade: {margin} B)", "restore_not_enough_disk_space": "Non hai espazo abondo (espazo: {free_space.d} B, espazo necesario: {needed_space} B, marxe de seguridade: {margin} B)",
@ -593,7 +588,7 @@
"user_updated": "Cambiada a info da usuaria", "user_updated": "Cambiada a info da usuaria",
"user_update_failed": "Non se actualizou usuaria {user}: {error}", "user_update_failed": "Non se actualizou usuaria {user}: {error}",
"user_unknown": "Usuaria descoñecida: {user}", "user_unknown": "Usuaria descoñecida: {user}",
"user_home_creation_failed": "Non se puido crear cartafol 'home' para a usuaria", "user_home_creation_failed": "Non se puido crear cartafol home '{home}' para a usuaria",
"user_deletion_failed": "Non se puido eliminar a usuaria {user}: {error}", "user_deletion_failed": "Non se puido eliminar a usuaria {user}: {error}",
"user_deleted": "Usuaria eliminada", "user_deleted": "Usuaria eliminada",
"user_creation_failed": "Non se puido crear a usuaria {user}: {error}", "user_creation_failed": "Non se puido crear a usuaria {user}: {error}",
@ -613,11 +608,11 @@
"unbackup_app": "{app} non vai ser gardada", "unbackup_app": "{app} non vai ser gardada",
"tools_upgrade_special_packages_completed": "Completada a actualización dos paquetes YunoHost.\nPreme [Enter] para recuperar a liña de comandos", "tools_upgrade_special_packages_completed": "Completada a actualización dos paquetes YunoHost.\nPreme [Enter] para recuperar a liña de comandos",
"tools_upgrade_special_packages_explanation": "A actualización especial continuará en segundo plano. Non inicies outras tarefas no servidor nos seguintes ~10 minutos (depende do hardware). Após isto, podes volver a conectar na webadmin. O rexistro da actualización estará dispoñible en Ferramentas → Rexistro (na webadmin) ou con 'yunohost log list' (na liña de comandos).", "tools_upgrade_special_packages_explanation": "A actualización especial continuará en segundo plano. Non inicies outras tarefas no servidor nos seguintes ~10 minutos (depende do hardware). Após isto, podes volver a conectar na webadmin. O rexistro da actualización estará dispoñible en Ferramentas → Rexistro (na webadmin) ou con 'yunohost log list' (na liña de comandos).",
"tools_upgrade_special_packages": "Actualizando paquetes 'special' (yunohost-related)", "tools_upgrade_special_packages": "Actualizando paquetes 'special' (yunohost-related)...",
"tools_upgrade_regular_packages_failed": "Non se actualizaron os paquetes: {packages_list}", "tools_upgrade_regular_packages_failed": "Non se actualizaron os paquetes: {packages_list}",
"tools_upgrade_regular_packages": "Actualizando os paquetes 'regular' (non-yunohost-related)", "tools_upgrade_regular_packages": "Actualizando os paquetes 'regular' (non-yunohost-related)...",
"tools_upgrade_cant_unhold_critical_packages": "Non se desbloquearon os paquetes críticos", "tools_upgrade_cant_unhold_critical_packages": "Non se desbloquearon os paquetes críticos...",
"tools_upgrade_cant_hold_critical_packages": "Non se puideron bloquear os paquetes críticos", "tools_upgrade_cant_hold_critical_packages": "Non se puideron bloquear os paquetes críticos...",
"tools_upgrade_cant_both": "Non se pode actualizar o sistema e as apps ao mesmo tempo", "tools_upgrade_cant_both": "Non se pode actualizar o sistema e as apps ao mesmo tempo",
"tools_upgrade_at_least_one": "Por favor indica 'apps', ou 'system'", "tools_upgrade_at_least_one": "Por favor indica 'apps', ou 'system'",
"this_action_broke_dpkg": "Esta acción rachou dpkg/APT (xestores de paquetes do sistema)... Podes intentar resolver o problema conectando a través de SSH e executando `sudo apt install --fix-broken`e/ou `sudo dpkg --configure -a`.", "this_action_broke_dpkg": "Esta acción rachou dpkg/APT (xestores de paquetes do sistema)... Podes intentar resolver o problema conectando a través de SSH e executando `sudo apt install --fix-broken`e/ou `sudo dpkg --configure -a`.",
@ -641,5 +636,44 @@
"service_removed": "Eliminado o servizo '{service}'", "service_removed": "Eliminado o servizo '{service}'",
"service_remove_failed": "Non se eliminou o servizo '{service}'", "service_remove_failed": "Non se eliminou o servizo '{service}'",
"service_regen_conf_is_deprecated": "'yunohost service regen-conf' xa non se utiliza! Executa 'yunohost tools regen-conf' no seu lugar.", "service_regen_conf_is_deprecated": "'yunohost service regen-conf' xa non se utiliza! Executa 'yunohost tools regen-conf' no seu lugar.",
"service_enabled": "O servizo '{service}' vai ser iniciado automáticamente no inicio do sistema." "service_enabled": "O servizo '{service}' vai ser iniciado automáticamente no inicio do sistema.",
} "diagnosis_apps_allgood": "Tódalas apps instaladas respectan as prácticas básicas de empaquetado",
"diagnosis_apps_bad_quality": "Esta aplicación está actualmente marcada como estragada no catálogo de aplicacións de YunoHost. Podería ser un problema temporal mentras as mantedoras intentan arranxar o problema. Ata ese momento a actualización desta app está desactivada.",
"global_settings_setting_security_nginx_redirect_to_https": "Redirixir peticións HTTP a HTTPs por defecto (NON DESACTIVAR ISTO a non ser que realmente saibas o que fas!)",
"log_user_import": "Importar usuarias",
"user_import_failed": "A operación de importación de usuarias fracasou",
"user_import_missing_columns": "Faltan as seguintes columnas: {columns}",
"user_import_nothing_to_do": "Ningunha usuaria precisa ser importada",
"user_import_partial_failed": "A operación de importación de usuarias fallou parcialmente",
"diagnosis_apps_deprecated_practices": "A versión instalada desta app aínda utiliza algunha das antigas prácticas de empaquetado xa abandonadas. Deberías considerar actualizala.",
"diagnosis_apps_outdated_ynh_requirement": "A versión instalada desta app só require yunohost >= 2.x, que normalmente indica que non está ao día coas prácticas recomendadas de empaquetado e asistentes. Deberías considerar actualizala.",
"user_import_success": "Usuarias importadas correctamente",
"diagnosis_high_number_auth_failures": "Hai un alto número sospeitoso de intentos fallidos de autenticación. Deberías comprobar que fail2ban está a executarse e que está correctamente configurado, ou utiliza un porto personalizado para SSH tal como se explica en https://yunohost.org/security.",
"user_import_bad_file": "O ficheiro CSV non ten o formato correcto e será ignorado para evitar unha potencial perda de datos",
"user_import_bad_line": "Liña incorrecta {line}: {details}",
"diagnosis_description_apps": "Aplicacións",
"diagnosis_apps_broken": "Actualmente esta aplicación está marcada como estragada no catálogo de aplicacións de YunoHost. Podería tratarse dun problema temporal mentras as mantedoras intentan arraxala. Entanto así a actualización da app está desactivada.",
"diagnosis_apps_issue": "Atopouse un problema na app {app}",
"diagnosis_apps_not_in_app_catalog": "Esta aplicación non está no catálgo de aplicacións de YunoHost. Se estivo no pasado e foi eliminada, deberías considerar desinstalala porque non recibirá actualizacións, e podería comprometer a integridade e seguridade do teu sistema.",
"app_argument_password_help_optional": "Escribe un espazo para limpar o contrasinal",
"config_validate_date": "Debe ser unha data válida co formato YYYY-MM-DD",
"config_validate_email": "Debe ser un email válido",
"config_validate_time": "Debe ser unha hora válida tal que HH:MM",
"config_validate_url": "Debe ser un URL válido",
"danger": "Perigo:",
"app_argument_password_help_keep": "Preme Enter para manter o valor actual",
"app_config_unable_to_read": "Fallou a lectura dos valores de configuración.",
"config_apply_failed": "Fallou a aplicación da nova configuración: {error}",
"config_forbidden_keyword": "O palabra chave '{keyword}' está reservada, non podes crear ou usar un panel de configuración cunha pregunta con este id.",
"config_no_panel": "Non se atopa panel configurado.",
"config_unknown_filter_key": "A chave do filtro '{filter_key}' non é correcta.",
"config_validate_color": "Debe ser un valor RGB hexadecimal válido",
"invalid_number_min": "Ten que ser maior que {min}",
"log_app_config_set": "Aplicar a configuración á app '{}'",
"app_config_unable_to_apply": "Fallou a aplicación dos valores de configuración.",
"config_cant_set_value_on_section": "Non podes establecer un valor único na sección completa de configuración.",
"config_version_not_supported": "A versión do panel de configuración '{version}' non está soportada.",
"file_extension_not_accepted": "Rexeitouse o ficheiro '{path}' porque a súa extensión non está entre as aceptadas: {accept}",
"invalid_number_max": "Ten que ser menor de {max}",
"service_not_reloading_because_conf_broken": "Non se recargou/reiniciou o servizo '{name}' porque a súa configuración está estragada: {errors}"
}

1
locales/id.json Normal file
View file

@ -0,0 +1 @@
{}

View file

@ -42,7 +42,7 @@
"ask_new_admin_password": "Nuova password dell'amministrazione", "ask_new_admin_password": "Nuova password dell'amministrazione",
"backup_app_failed": "Non è possibile fare il backup {app}", "backup_app_failed": "Non è possibile fare il backup {app}",
"backup_archive_app_not_found": "{app} non è stata trovata nel archivio di backup", "backup_archive_app_not_found": "{app} non è stata trovata nel archivio di backup",
"app_argument_choice_invalid": "Usa una delle seguenti scelte '{choices}' per il parametro '{name}'", "app_argument_choice_invalid": "Usa una delle seguenti scelte '{choices}' per il parametro '{name}' invece di '{value}'",
"app_argument_invalid": "Scegli un valore valido per il parametro '{name}': {error}", "app_argument_invalid": "Scegli un valore valido per il parametro '{name}': {error}",
"app_argument_required": "L'argomento '{name}' è requisito", "app_argument_required": "L'argomento '{name}' è requisito",
"app_id_invalid": "Identificativo dell'applicazione non valido", "app_id_invalid": "Identificativo dell'applicazione non valido",
@ -67,7 +67,6 @@
"domain_dyndns_root_unknown": "Dominio radice DynDNS sconosciuto", "domain_dyndns_root_unknown": "Dominio radice DynDNS sconosciuto",
"domain_hostname_failed": "Impossibile impostare il nuovo hostname. Potrebbe causare problemi in futuro (o anche no).", "domain_hostname_failed": "Impossibile impostare il nuovo hostname. Potrebbe causare problemi in futuro (o anche no).",
"domain_uninstall_app_first": "Queste applicazioni sono già installate su questo dominio:\n{apps}\n\nDisinstallale eseguendo 'yunohost app remove app_id' o spostale in un altro dominio eseguendo 'yunohost app change-url app_id' prima di procedere alla cancellazione del dominio", "domain_uninstall_app_first": "Queste applicazioni sono già installate su questo dominio:\n{apps}\n\nDisinstallale eseguendo 'yunohost app remove app_id' o spostale in un altro dominio eseguendo 'yunohost app change-url app_id' prima di procedere alla cancellazione del dominio",
"domain_unknown": "Dominio sconosciuto",
"done": "Terminato", "done": "Terminato",
"domains_available": "Domini disponibili:", "domains_available": "Domini disponibili:",
"downloading": "Scaricamento…", "downloading": "Scaricamento…",
@ -104,7 +103,6 @@
"pattern_lastname": "Deve essere un cognome valido", "pattern_lastname": "Deve essere un cognome valido",
"pattern_password": "Deve contenere almeno 3 caratteri", "pattern_password": "Deve contenere almeno 3 caratteri",
"pattern_port_or_range": "Deve essere un numero di porta valido (es. 0-65535) o una fascia di porte valida (es. 100:200)", "pattern_port_or_range": "Deve essere un numero di porta valido (es. 0-65535) o una fascia di porte valida (es. 100:200)",
"pattern_positive_number": "Deve essere un numero positivo",
"pattern_username": "Caratteri minuscoli alfanumerici o trattini bassi soli", "pattern_username": "Caratteri minuscoli alfanumerici o trattini bassi soli",
"port_already_closed": "La porta {port} è già chiusa per le connessioni {ip_version}", "port_already_closed": "La porta {port} è già chiusa per le connessioni {ip_version}",
"restore_already_installed_app": "Un'applicazione con l'ID '{app}' è già installata", "restore_already_installed_app": "Un'applicazione con l'ID '{app}' è già installata",
@ -116,8 +114,8 @@
"user_update_failed": "Impossibile aggiornare l'utente {user}: {error}", "user_update_failed": "Impossibile aggiornare l'utente {user}: {error}",
"restore_hook_unavailable": "Lo script di ripristino per '{part}' non è disponibile per il tuo sistema e non è nemmeno nell'archivio", "restore_hook_unavailable": "Lo script di ripristino per '{part}' non è disponibile per il tuo sistema e non è nemmeno nell'archivio",
"restore_nothings_done": "Nulla è stato ripristinato", "restore_nothings_done": "Nulla è stato ripristinato",
"restore_running_app_script": "Ripristino dell'app '{app}'", "restore_running_app_script": "Ripristino dell'app '{app}'...",
"restore_running_hooks": "Esecuzione degli hook di ripristino", "restore_running_hooks": "Esecuzione degli hook di ripristino...",
"service_added": "Il servizio '{service}' è stato aggiunto", "service_added": "Il servizio '{service}' è stato aggiunto",
"service_already_started": "Il servizio '{service}' è già avviato", "service_already_started": "Il servizio '{service}' è già avviato",
"service_already_stopped": "Il servizio '{service}' è già stato fermato", "service_already_stopped": "Il servizio '{service}' è già stato fermato",
@ -143,7 +141,7 @@
"user_created": "Utente creato", "user_created": "Utente creato",
"user_creation_failed": "Impossibile creare l'utente {user}: {error}", "user_creation_failed": "Impossibile creare l'utente {user}: {error}",
"user_deletion_failed": "Impossibile cancellare l'utente {user}: {error}", "user_deletion_failed": "Impossibile cancellare l'utente {user}: {error}",
"user_home_creation_failed": "Impossibile creare la 'home' directory del utente", "user_home_creation_failed": "Impossibile creare la home directory '{home}' del utente",
"user_unknown": "Utente sconosciuto: {user}", "user_unknown": "Utente sconosciuto: {user}",
"user_updated": "Info dell'utente cambiate", "user_updated": "Info dell'utente cambiate",
"yunohost_already_installed": "YunoHost è già installato", "yunohost_already_installed": "YunoHost è già installato",
@ -159,7 +157,6 @@
"certmanager_domain_http_not_working": "Il dominio {domain} non sembra accessibile attraverso HTTP. Verifica nella sezione 'Web' nella diagnosi per maggiori informazioni. (Se sai cosa stai facendo, usa '--no-checks' per disattivare i controlli.)", "certmanager_domain_http_not_working": "Il dominio {domain} non sembra accessibile attraverso HTTP. Verifica nella sezione 'Web' nella diagnosi per maggiori informazioni. (Se sai cosa stai facendo, usa '--no-checks' per disattivare i controlli.)",
"app_already_installed_cant_change_url": "Questa applicazione è già installata. L'URL non può essere cambiato solo da questa funzione. Controlla se `app changeurl` è disponibile.", "app_already_installed_cant_change_url": "Questa applicazione è già installata. L'URL non può essere cambiato solo da questa funzione. Controlla se `app changeurl` è disponibile.",
"app_already_up_to_date": "{app} è già aggiornata", "app_already_up_to_date": "{app} è già aggiornata",
"app_change_url_failed_nginx_reload": "Non riesco a riavviare NGINX. Questo è il risultato di 'nginx -t':\n{nginx_errors}",
"app_change_url_identical_domains": "Il vecchio ed il nuovo dominio/percorso_url sono identici ('{domain}{path}'), nessuna operazione necessaria.", "app_change_url_identical_domains": "Il vecchio ed il nuovo dominio/percorso_url sono identici ('{domain}{path}'), nessuna operazione necessaria.",
"app_change_url_no_script": "L'applicazione '{app_name}' non supporta ancora la modifica dell'URL. Forse dovresti aggiornarla.", "app_change_url_no_script": "L'applicazione '{app_name}' non supporta ancora la modifica dell'URL. Forse dovresti aggiornarla.",
"app_change_url_success": "L'URL dell'applicazione {app} è stato cambiato in {domain}{path}", "app_change_url_success": "L'URL dell'applicazione {app} è stato cambiato in {domain}{path}",
@ -249,7 +246,7 @@
"good_practices_about_admin_password": "Stai per impostare una nuova password di amministratore. La password deve essere almeno di 8 caratteri - anche se è buona pratica utilizzare password più lunghe (es. una frase, una serie di parole) e/o utilizzare vari tipi di caratteri (maiuscole, minuscole, numeri e simboli).", "good_practices_about_admin_password": "Stai per impostare una nuova password di amministratore. La password deve essere almeno di 8 caratteri - anche se è buona pratica utilizzare password più lunghe (es. una frase, una serie di parole) e/o utilizzare vari tipi di caratteri (maiuscole, minuscole, numeri e simboli).",
"log_corrupted_md_file": "Il file dei metadati YAML associato con i registri è danneggiato: '{md_file}'\nErrore: {error}", "log_corrupted_md_file": "Il file dei metadati YAML associato con i registri è danneggiato: '{md_file}'\nErrore: {error}",
"log_link_to_log": "Registro completo di questa operazione: '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>'", "log_link_to_log": "Registro completo di questa operazione: '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>'",
"log_help_to_get_log": "Per vedere il registro dell'operazione '{desc}', usa il comando 'yunohost log show {name}{name}'", "log_help_to_get_log": "Per vedere il registro dell'operazione '{desc}', usa il comando 'yunohost log show {name}'",
"global_settings_setting_security_postfix_compatibility": "Bilanciamento tra compatibilità e sicurezza per il server Postfix. Riguarda gli algoritmi di cifratura (e altri aspetti legati alla sicurezza)", "global_settings_setting_security_postfix_compatibility": "Bilanciamento tra compatibilità e sicurezza per il server Postfix. Riguarda gli algoritmi di cifratura (e altri aspetti legati alla sicurezza)",
"log_link_to_failed_log": "Impossibile completare l'operazione '{desc}'! Per ricevere aiuto, per favore fornisci il registro completo dell'operazione <a href=\"#/tools/logs/{name}\">cliccando qui</a>", "log_link_to_failed_log": "Impossibile completare l'operazione '{desc}'! Per ricevere aiuto, per favore fornisci il registro completo dell'operazione <a href=\"#/tools/logs/{name}\">cliccando qui</a>",
"log_help_to_get_failed_log": "L'operazione '{desc}' non può essere completata. Per ottenere aiuto, per favore condividi il registro completo dell'operazione utilizzando il comando 'yunohost log share {name}'", "log_help_to_get_failed_log": "L'operazione '{desc}' non può essere completata. Per ottenere aiuto, per favore condividi il registro completo dell'operazione utilizzando il comando 'yunohost log share {name}'",
@ -398,11 +395,11 @@
"unknown_main_domain_path": "Percorso o dominio sconosciuto per '{app}'. Devi specificare un dominio e un percorso per poter specificare un URL per il permesso.", "unknown_main_domain_path": "Percorso o dominio sconosciuto per '{app}'. Devi specificare un dominio e un percorso per poter specificare un URL per il permesso.",
"tools_upgrade_special_packages_completed": "Aggiornamento pacchetti YunoHost completato.\nPremi [Invio] per tornare al terminale", "tools_upgrade_special_packages_completed": "Aggiornamento pacchetti YunoHost completato.\nPremi [Invio] per tornare al terminale",
"tools_upgrade_special_packages_explanation": "L'aggiornamento speciale continuerà in background. Per favore non iniziare nessun'altra azione sul tuo server per i prossimi ~10 minuti (dipende dalla velocità hardware). Dopo questo, dovrai ri-loggarti nel webadmin. Il registro di aggiornamento sarà disponibile in Strumenti → Log/Registri (nel webadmin) o dalla linea di comando eseguendo 'yunohost log list'.", "tools_upgrade_special_packages_explanation": "L'aggiornamento speciale continuerà in background. Per favore non iniziare nessun'altra azione sul tuo server per i prossimi ~10 minuti (dipende dalla velocità hardware). Dopo questo, dovrai ri-loggarti nel webadmin. Il registro di aggiornamento sarà disponibile in Strumenti → Log/Registri (nel webadmin) o dalla linea di comando eseguendo 'yunohost log list'.",
"tools_upgrade_special_packages": "Adesso aggiorno i pacchetti 'speciali' (correlati a yunohost)", "tools_upgrade_special_packages": "Adesso aggiorno i pacchetti 'speciali' (correlati a yunohost)...",
"tools_upgrade_regular_packages_failed": "Impossibile aggiornare i pacchetti: {packages_list}", "tools_upgrade_regular_packages_failed": "Impossibile aggiornare i pacchetti: {packages_list}",
"tools_upgrade_regular_packages": "Adesso aggiorno i pacchetti 'normali' (non correlati a yunohost)", "tools_upgrade_regular_packages": "Adesso aggiorno i pacchetti 'normali' (non correlati a yunohost)...",
"tools_upgrade_cant_unhold_critical_packages": "Impossibile annullare il blocco dei pacchetti critici/importanti", "tools_upgrade_cant_unhold_critical_packages": "Impossibile annullare il blocco dei pacchetti critici/importanti...",
"tools_upgrade_cant_hold_critical_packages": "Impossibile bloccare i pacchetti critici/importanti", "tools_upgrade_cant_hold_critical_packages": "Impossibile bloccare i pacchetti critici/importanti...",
"tools_upgrade_cant_both": "Impossibile aggiornare sia il sistema e le app nello stesso momento", "tools_upgrade_cant_both": "Impossibile aggiornare sia il sistema e le app nello stesso momento",
"tools_upgrade_at_least_one": "Specifica 'apps', o 'system'", "tools_upgrade_at_least_one": "Specifica 'apps', o 'system'",
"show_tile_cant_be_enabled_for_regex": "Non puoi abilitare 'show_tile' in questo momento, perché l'URL del permesso '{permission}' è una regex", "show_tile_cant_be_enabled_for_regex": "Non puoi abilitare 'show_tile' in questo momento, perché l'URL del permesso '{permission}' è una regex",
@ -438,14 +435,14 @@
"restore_removing_tmp_dir_failed": "Impossibile rimuovere una vecchia directory temporanea", "restore_removing_tmp_dir_failed": "Impossibile rimuovere una vecchia directory temporanea",
"restore_not_enough_disk_space": "Spazio libero insufficiente (spazio: {free_space}B, necessario: {needed_space}B, margine di sicurezza: {margin}B)", "restore_not_enough_disk_space": "Spazio libero insufficiente (spazio: {free_space}B, necessario: {needed_space}B, margine di sicurezza: {margin}B)",
"restore_may_be_not_enough_disk_space": "Il tuo sistema non sembra avere abbastanza spazio (libero: {free_space}B, necessario: {needed_space}B, margine di sicurezza: {margin}B)", "restore_may_be_not_enough_disk_space": "Il tuo sistema non sembra avere abbastanza spazio (libero: {free_space}B, necessario: {needed_space}B, margine di sicurezza: {margin}B)",
"restore_extracting": "Sto estraendo i file necessari dall'archivio", "restore_extracting": "Sto estraendo i file necessari dall'archivio...",
"restore_already_installed_apps": "Le seguenti app non possono essere ripristinate perché sono già installate: {apps}", "restore_already_installed_apps": "Le seguenti app non possono essere ripristinate perché sono già installate: {apps}",
"regex_with_only_domain": "Non puoi usare una regex per il dominio, solo per i percorsi", "regex_with_only_domain": "Non puoi usare una regex per il dominio, solo per i percorsi",
"regex_incompatible_with_tile": "/!\\ Packagers! Il permesso '{permission}' ha show_tile impostato su 'true' e perciò non è possibile definire un URL regex per l'URL principale", "regex_incompatible_with_tile": "/!\\ Packagers! Il permesso '{permission}' ha show_tile impostato su 'true' e perciò non è possibile definire un URL regex per l'URL principale",
"regenconf_need_to_explicitly_specify_ssh": "La configurazione ssh è stata modificata manualmente, ma devi specificare la categoria 'ssh' con --force per applicare le modifiche.", "regenconf_need_to_explicitly_specify_ssh": "La configurazione ssh è stata modificata manualmente, ma devi specificare la categoria 'ssh' con --force per applicare le modifiche.",
"regenconf_pending_applying": "Applico le configurazioni in attesa per la categoria '{category}'...", "regenconf_pending_applying": "Applico le configurazioni in attesa per la categoria '{category}'...",
"regenconf_failed": "Impossibile rigenerare la configurazione per le categorie: {categories}", "regenconf_failed": "Impossibile rigenerare la configurazione per le categorie: {categories}",
"regenconf_dry_pending_applying": "Controllo configurazioni in attesa che potrebbero essere applicate alla categoria '{category}'", "regenconf_dry_pending_applying": "Controllo configurazioni in attesa che potrebbero essere applicate alla categoria '{category}'...",
"regenconf_would_be_updated": "La configurazione sarebbe stata aggiornata per la categoria '{category}'", "regenconf_would_be_updated": "La configurazione sarebbe stata aggiornata per la categoria '{category}'",
"regenconf_updated": "Configurazione aggiornata per '{category}'", "regenconf_updated": "Configurazione aggiornata per '{category}'",
"regenconf_up_to_date": "Il file di configurazione è già aggiornato per la categoria '{category}'", "regenconf_up_to_date": "Il file di configurazione è già aggiornato per la categoria '{category}'",
@ -531,8 +528,6 @@
"log_permission_url": "Aggiorna l'URL collegato al permesso '{}'", "log_permission_url": "Aggiorna l'URL collegato al permesso '{}'",
"log_permission_delete": "Cancella permesso '{}'", "log_permission_delete": "Cancella permesso '{}'",
"log_permission_create": "Crea permesso '{}'", "log_permission_create": "Crea permesso '{}'",
"log_app_config_apply": "Applica la configurazione all'app '{}'",
"log_app_config_show_panel": "Mostra il pannello di configurazione dell'app '{}'",
"log_app_action_run": "Esegui l'azione dell'app '{}'", "log_app_action_run": "Esegui l'azione dell'app '{}'",
"log_operation_unit_unclosed_properly": "Operazion unit non è stata chiusa correttamente", "log_operation_unit_unclosed_properly": "Operazion unit non è stata chiusa correttamente",
"invalid_regex": "Regex invalida:'{regex}'", "invalid_regex": "Regex invalida:'{regex}'",

1
locales/mk.json Normal file
View file

@ -0,0 +1 @@
{}

View file

@ -27,7 +27,6 @@
"app_action_cannot_be_ran_because_required_services_down": "Dette programmet krever noen tjenester som ikke kjører. Før du fortsetter, du bør prøve å starte følgende tjenester på ny (og antagelig undersøke hvorfor de er nede): {services}", "app_action_cannot_be_ran_because_required_services_down": "Dette programmet krever noen tjenester som ikke kjører. Før du fortsetter, du bør prøve å starte følgende tjenester på ny (og antagelig undersøke hvorfor de er nede): {services}",
"app_already_installed_cant_change_url": "Dette programmet er allerede installert. Nettadressen kan ikke endres kun med denne funksjonen. Ta en titt på `app changeurl` hvis den er tilgjengelig.", "app_already_installed_cant_change_url": "Dette programmet er allerede installert. Nettadressen kan ikke endres kun med denne funksjonen. Ta en titt på `app changeurl` hvis den er tilgjengelig.",
"domain_exists": "Domenet finnes allerede", "domain_exists": "Domenet finnes allerede",
"app_change_url_failed_nginx_reload": "Kunne ikke gjeninnlaste NGINX. Her har du utdataen for 'nginx -t'\n{nginx_errors}",
"domains_available": "Tilgjengelige domener:", "domains_available": "Tilgjengelige domener:",
"done": "Ferdig", "done": "Ferdig",
"downloading": "Laster ned…", "downloading": "Laster ned…",
@ -83,7 +82,6 @@
"domain_created": "Domene opprettet", "domain_created": "Domene opprettet",
"domain_creation_failed": "Kunne ikke opprette domene", "domain_creation_failed": "Kunne ikke opprette domene",
"domain_dyndns_root_unknown": "Ukjent DynDNS-rotdomene", "domain_dyndns_root_unknown": "Ukjent DynDNS-rotdomene",
"domain_unknown": "Ukjent domene",
"dyndns_ip_update_failed": "Kunne ikke oppdatere IP-adresse til DynDNS", "dyndns_ip_update_failed": "Kunne ikke oppdatere IP-adresse til DynDNS",
"dyndns_ip_updated": "Oppdaterte din IP på DynDNS", "dyndns_ip_updated": "Oppdaterte din IP på DynDNS",
"dyndns_key_generating": "Oppretter DNS-nøkkel… Dette kan ta en stund.", "dyndns_key_generating": "Oppretter DNS-nøkkel… Dette kan ta en stund.",
@ -115,7 +113,7 @@
"domain_deletion_failed": "Kunne ikke slette domene", "domain_deletion_failed": "Kunne ikke slette domene",
"domain_dyndns_already_subscribed": "Du har allerede abonnement på et DynDNS-domene", "domain_dyndns_already_subscribed": "Du har allerede abonnement på et DynDNS-domene",
"log_link_to_log": "Full logg for denne operasjonen: '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>'", "log_link_to_log": "Full logg for denne operasjonen: '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>'",
"log_help_to_get_log": "For å vise loggen for operasjonen '{desc}', bruk kommandoen 'yunohost log show {name}{name}'", "log_help_to_get_log": "For å vise loggen for operasjonen '{desc}', bruk kommandoen 'yunohost log show {name}'",
"log_user_create": "Legg til '{}' bruker", "log_user_create": "Legg til '{}' bruker",
"app_change_url_success": "{app} nettadressen er nå {domain}{path}", "app_change_url_success": "{app} nettadressen er nå {domain}{path}",
"app_install_failed": "Kunne ikke installere {app}: {error}" "app_install_failed": "Kunne ikke installere {app}: {error}"

View file

@ -32,7 +32,6 @@
"domain_dyndns_root_unknown": "Onbekend DynDNS root domein", "domain_dyndns_root_unknown": "Onbekend DynDNS root domein",
"domain_exists": "Domein bestaat al", "domain_exists": "Domein bestaat al",
"domain_uninstall_app_first": "Een of meerdere apps zijn geïnstalleerd op dit domein, verwijder deze voordat u het domein verwijdert", "domain_uninstall_app_first": "Een of meerdere apps zijn geïnstalleerd op dit domein, verwijder deze voordat u het domein verwijdert",
"domain_unknown": "Onbekend domein",
"done": "Voltooid", "done": "Voltooid",
"downloading": "Downloaden...", "downloading": "Downloaden...",
"dyndns_ip_update_failed": "Kan het IP adres niet updaten bij DynDNS", "dyndns_ip_update_failed": "Kan het IP adres niet updaten bij DynDNS",
@ -102,7 +101,6 @@
"app_manifest_install_ask_domain": "Kies het domein waar deze app op geïnstalleerd moet worden", "app_manifest_install_ask_domain": "Kies het domein waar deze app op geïnstalleerd moet worden",
"app_manifest_install_ask_path": "Kies het pad waar deze app geïnstalleerd moet worden", "app_manifest_install_ask_path": "Kies het pad waar deze app geïnstalleerd moet worden",
"app_manifest_install_ask_admin": "Kies een administrator voor deze app", "app_manifest_install_ask_admin": "Kies een administrator voor deze app",
"app_change_url_failed_nginx_reload": "Kon NGINX niet opnieuw laden. Hier is de output van 'nginx -t':\n{nginx_errors}",
"app_change_url_success": "{app} URL is nu {domain}{path}", "app_change_url_success": "{app} URL is nu {domain}{path}",
"app_full_domain_unavailable": "Sorry, deze app moet op haar eigen domein geïnstalleerd worden, maar andere apps zijn al geïnstalleerd op het domein '{domain}'. U kunt wel een subdomein aan deze app toewijden.", "app_full_domain_unavailable": "Sorry, deze app moet op haar eigen domein geïnstalleerd worden, maar andere apps zijn al geïnstalleerd op het domein '{domain}'. U kunt wel een subdomein aan deze app toewijden.",
"app_install_script_failed": "Er is een fout opgetreden in het installatiescript van de app", "app_install_script_failed": "Er is een fout opgetreden in het installatiescript van de app",

View file

@ -30,7 +30,6 @@
"app_argument_choice_invalid": "Utilizatz una de las opcions « {choices} » per largument « {name} »", "app_argument_choice_invalid": "Utilizatz una de las opcions « {choices} » per largument « {name} »",
"app_argument_invalid": "Causissètz una valor invalida pel paramètre « {name} » : {error}", "app_argument_invalid": "Causissètz una valor invalida pel paramètre « {name} » : {error}",
"app_argument_required": "Lo paramètre « {name}»es requesit", "app_argument_required": "Lo paramètre « {name}»es requesit",
"app_change_url_failed_nginx_reload": "Reaviada de NGINX impossibla. Vaquí la sortida de «nginx -t»:\n{nginx_errors}",
"app_change_url_identical_domains": "Lancian e lo novèl coble domeni/camin son identics per {domain}{path}, pas res a far.", "app_change_url_identical_domains": "Lancian e lo novèl coble domeni/camin son identics per {domain}{path}, pas res a far.",
"app_change_url_success": "LURL de laplicacion {app} es ara {domain}{path}", "app_change_url_success": "LURL de laplicacion {app} es ara {domain}{path}",
"app_extraction_failed": "Extraccion dels fichièrs dinstallacion impossibla", "app_extraction_failed": "Extraccion dels fichièrs dinstallacion impossibla",
@ -108,7 +107,6 @@
"domain_dyndns_root_unknown": "Domeni DynDNS màger desconegut", "domain_dyndns_root_unknown": "Domeni DynDNS màger desconegut",
"domain_exists": "Lo domeni existís ja", "domain_exists": "Lo domeni existís ja",
"domain_hostname_failed": "Fracàs de la creacion dun nòu nom dòst. Aquò poirà provocar de problèmas mai tard (mas es pas segur… benlèu que coparà pas res).", "domain_hostname_failed": "Fracàs de la creacion dun nòu nom dòst. Aquò poirà provocar de problèmas mai tard (mas es pas segur… benlèu que coparà pas res).",
"domain_unknown": "Domeni desconegut",
"domains_available": "Domenis disponibles:", "domains_available": "Domenis disponibles:",
"done": "Acabat", "done": "Acabat",
"downloading": "Telecargament…", "downloading": "Telecargament…",
@ -141,7 +139,6 @@
"pattern_lastname": "Deu èsser un nom valid", "pattern_lastname": "Deu èsser un nom valid",
"pattern_password": "Deu conténer almens 3 caractèrs", "pattern_password": "Deu conténer almens 3 caractèrs",
"pattern_port_or_range": "Deu èsser un numèro de pòrt valid (ex: 0-65535) o un interval de pòrt (ex: 100:200)", "pattern_port_or_range": "Deu èsser un numèro de pòrt valid (ex: 0-65535) o un interval de pòrt (ex: 100:200)",
"pattern_positive_number": "Deu èsser un nombre positiu",
"port_already_closed": "Lo pòrt {port} es ja tampat per las connexions {ip_version}", "port_already_closed": "Lo pòrt {port} es ja tampat per las connexions {ip_version}",
"port_already_opened": "Lo pòrt {port} es ja dubèrt per las connexions {ip_version}", "port_already_opened": "Lo pòrt {port} es ja dubèrt per las connexions {ip_version}",
"restore_already_installed_app": "Una aplicacion es ja installada amb lid « {app} »", "restore_already_installed_app": "Una aplicacion es ja installada amb lid « {app} »",
@ -248,7 +245,7 @@
"experimental_feature": "Atencion: aquesta foncionalitat es experimentala e deu pas èsser considerada coma establa, deuriatz pas lutilizar levat que sapiatz çò que fasètz.", "experimental_feature": "Atencion: aquesta foncionalitat es experimentala e deu pas èsser considerada coma establa, deuriatz pas lutilizar levat que sapiatz çò que fasètz.",
"log_corrupted_md_file": "Lo fichièr YAML de metadonadas ligat als jornals daudit es damatjat: « {md_file} »\nError: {error}", "log_corrupted_md_file": "Lo fichièr YAML de metadonadas ligat als jornals daudit es damatjat: « {md_file} »\nError: {error}",
"log_link_to_log": "Jornal complèt daquesta operacion: <a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>", "log_link_to_log": "Jornal complèt daquesta operacion: <a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>",
"log_help_to_get_log": "Per veire lo jornal daquesta operacion « {desc} », utilizatz la comanda «yunohost log show {name}{name} »", "log_help_to_get_log": "Per veire lo jornal daquesta operacion « {desc} », utilizatz la comanda «yunohost log show {name} »",
"log_link_to_failed_log": "Loperacion « {desc} » a pas capitat! Per obténer dajuda, mercés <a href=\"#/tools/logs/{name}\"> de fornir lo jornal complèt de loperacion</a>", "log_link_to_failed_log": "Loperacion « {desc} » a pas capitat! Per obténer dajuda, mercés <a href=\"#/tools/logs/{name}\"> de fornir lo jornal complèt de loperacion</a>",
"log_help_to_get_failed_log": "Loperacion « {desc} » a pas reüssit! Per obténer dajuda, mercés de partejar lo jornal daudit complèt daquesta operacion en utilizant la comanda «yunohost log share {name} »", "log_help_to_get_failed_log": "Loperacion « {desc} » a pas reüssit! Per obténer dajuda, mercés de partejar lo jornal daudit complèt daquesta operacion en utilizant la comanda «yunohost log share {name} »",
"log_does_exists": "I a pas cap de jornal daudit per loperacion amb lo nom « {log} », utilizatz «yunohost log list» per veire totes los jornals doperacion disponibles", "log_does_exists": "I a pas cap de jornal daudit per loperacion amb lo nom « {log} », utilizatz «yunohost log list» per veire totes los jornals doperacion disponibles",
@ -448,7 +445,7 @@
"diagnosis_ports_could_not_diagnose_details": "Error : {error}", "diagnosis_ports_could_not_diagnose_details": "Error : {error}",
"diagnosis_http_could_not_diagnose": "Impossible de diagnosticar se lo domeni es accessible de lexterior.", "diagnosis_http_could_not_diagnose": "Impossible de diagnosticar se lo domeni es accessible de lexterior.",
"diagnosis_http_could_not_diagnose_details": "Error : {error}", "diagnosis_http_could_not_diagnose_details": "Error : {error}",
"apps_catalog_updating": "Actualizacion del catalòg daplicacion", "apps_catalog_updating": "Actualizacion del catalòg daplicacion...",
"apps_catalog_failed_to_download": "Telecargament impossible del catalòg daplicacions {apps_catalog} : {error}", "apps_catalog_failed_to_download": "Telecargament impossible del catalòg daplicacions {apps_catalog} : {error}",
"apps_catalog_obsolete_cache": "La memòria cache del catalòg daplicacion es voida o obsolèta.", "apps_catalog_obsolete_cache": "La memòria cache del catalòg daplicacion es voida o obsolèta.",
"apps_catalog_update_success": "Lo catalòg daplicacions es a jorn !", "apps_catalog_update_success": "Lo catalòg daplicacions es a jorn !",
@ -504,8 +501,6 @@
"migration_description_0016_php70_to_php73_pools": "Migrar los fichièrs de configuracion php7.0 cap a php7.3", "migration_description_0016_php70_to_php73_pools": "Migrar los fichièrs de configuracion php7.0 cap a php7.3",
"migration_description_0015_migrate_to_buster": "Mesa a nivèl dels sistèmas Debian Buster e YunoHost 4.x", "migration_description_0015_migrate_to_buster": "Mesa a nivèl dels sistèmas Debian Buster e YunoHost 4.x",
"migrating_legacy_permission_settings": "Migracion dels paramètres de permission ancians...", "migrating_legacy_permission_settings": "Migracion dels paramètres de permission ancians...",
"log_app_config_apply": "Aplicar la configuracion a laplicacion « {} »",
"log_app_config_show_panel": "Mostrar lo panèl de configuracion de laplicacion « {} »",
"log_app_action_run": "Executar laccion de laplicacion « {} »", "log_app_action_run": "Executar laccion de laplicacion « {} »",
"diagnosis_basesystem_hardware_model": "Lo modèl del servidor es {model}", "diagnosis_basesystem_hardware_model": "Lo modèl del servidor es {model}",
"backup_archive_cant_retrieve_info_json": "Obtencion impossibla de las informacions de larchiu « {archive} »... Se pòt pas recuperar lo fichièr info.json (o es pas un fichièr json valid).", "backup_archive_cant_retrieve_info_json": "Obtencion impossibla de las informacions de larchiu « {archive} »... Se pòt pas recuperar lo fichièr info.json (o es pas un fichièr json valid).",

View file

@ -20,26 +20,25 @@
"ask_new_admin_password": "Nova senha de administração", "ask_new_admin_password": "Nova senha de administração",
"ask_password": "Senha", "ask_password": "Senha",
"backup_created": "Backup completo", "backup_created": "Backup completo",
"backup_output_directory_not_empty": "A pasta de destino não se encontra vazia", "backup_output_directory_not_empty": "Você deve escolher um diretório de saída que esteja vazio",
"custom_app_url_required": "Deve fornecer um link para atualizar a sua aplicação personalizada {app}", "custom_app_url_required": "Deve fornecer um link para atualizar a sua aplicação personalizada {app}",
"domain_cert_gen_failed": "Não foi possível gerar o certificado", "domain_cert_gen_failed": "Não foi possível gerar o certificado",
"domain_created": "Domínio criado com êxito", "domain_created": "Domínio criado com êxito",
"domain_creation_failed": "Não foi possível criar o domínio", "domain_creation_failed": "Não foi possível criar o domínio {domain}: {error}",
"domain_deleted": "Domínio removido com êxito", "domain_deleted": "Domínio removido com êxito",
"domain_deletion_failed": "Não foi possível eliminar o domínio", "domain_deletion_failed": "Não foi possível eliminar o domínio {domain}: {error}",
"domain_dyndns_already_subscribed": "Já subscreveu um domínio DynDNS", "domain_dyndns_already_subscribed": "Já subscreveu um domínio DynDNS",
"domain_dyndns_root_unknown": "Domínio root (administrador) DynDNS desconhecido", "domain_dyndns_root_unknown": "Domínio root (administrador) DynDNS desconhecido",
"domain_exists": "O domínio já existe", "domain_exists": "O domínio já existe",
"domain_uninstall_app_first": "Existem uma ou mais aplicações instaladas neste domínio. Por favor desinstale-as antes de proceder com a remoção do domínio.", "domain_uninstall_app_first": "Existem uma ou mais aplicações instaladas neste domínio. Por favor desinstale-as antes de proceder com a remoção do domínio.",
"domain_unknown": "Domínio desconhecido",
"done": "Concluído.", "done": "Concluído.",
"downloading": "Transferência em curso...", "downloading": "Transferência em curso...",
"dyndns_ip_update_failed": "Não foi possível atualizar o endereço IP a partir de DynDNS", "dyndns_ip_update_failed": "Não foi possível atualizar o endereço IP para DynDNS",
"dyndns_ip_updated": "Endereço IP atualizado com êxito a partir de DynDNS", "dyndns_ip_updated": "Endereço IP atualizado com êxito para DynDNS",
"dyndns_key_generating": "A chave DNS está a ser gerada, isto pode demorar um pouco...", "dyndns_key_generating": "A chave DNS está a ser gerada, isto pode demorar um pouco...",
"dyndns_registered": "Dom+inio DynDNS registado com êxito", "dyndns_registered": "Dom+inio DynDNS registado com êxito",
"dyndns_registration_failed": "Não foi possível registar o domínio DynDNS: {error}", "dyndns_registration_failed": "Não foi possível registar o domínio DynDNS: {error}",
"dyndns_unavailable": "Subdomínio DynDNS indisponível", "dyndns_unavailable": "O domínio '{domain}' não está disponível.",
"extracting": "Extração em curso...", "extracting": "Extração em curso...",
"field_invalid": "Campo inválido '{}'", "field_invalid": "Campo inválido '{}'",
"firewall_reloaded": "Firewall recarregada com êxito", "firewall_reloaded": "Firewall recarregada com êxito",
@ -97,34 +96,33 @@
"app_not_properly_removed": "{app} não foi corretamente removido", "app_not_properly_removed": "{app} não foi corretamente removido",
"app_requirements_checking": "Verificando os pacotes necessários para {app}...", "app_requirements_checking": "Verificando os pacotes necessários para {app}...",
"app_unsupported_remote_type": "A aplicação não possui suporte ao tipo remoto utilizado", "app_unsupported_remote_type": "A aplicação não possui suporte ao tipo remoto utilizado",
"backup_archive_app_not_found": "A aplicação '{app}' não foi encontrada no arquivo de backup", "backup_archive_app_not_found": "Não foi possível encontrar {app} no arquivo de backup",
"backup_archive_broken_link": "Impossível acessar o arquivo de backup (link quebrado ao {path})", "backup_archive_broken_link": "Não foi possível acessar o arquivo de backup (link quebrado ao {path})",
"backup_archive_name_exists": "O nome do arquivo de backup já existe", "backup_archive_name_exists": "Já existe um arquivo de backup com esse nome.",
"backup_archive_open_failed": "Não é possível abrir o arquivo de backup", "backup_archive_open_failed": "Não foi possível abrir o arquivo de backup",
"backup_cleaning_failed": "Não é possível limpar a pasta temporária de backups", "backup_cleaning_failed": "Não foi possível limpar o diretório temporário de backup",
"backup_creation_failed": "A criação do backup falhou", "backup_creation_failed": "Não foi possível criar o arquivo de backup",
"backup_delete_error": "Impossível apagar '{path}'", "backup_delete_error": "Não foi possível remover '{path}'",
"backup_deleted": "O backup foi suprimido", "backup_deleted": "Backup removido",
"backup_hook_unknown": "Gancho de backup '{hook}' desconhecido", "backup_hook_unknown": "O gancho de backup '{hook}' é desconhecido",
"backup_nothings_done": "Não há nada para guardar", "backup_nothings_done": "Nada há se salvar",
"backup_output_directory_forbidden": "Diretório de saída proibido. Os backups não podem ser criados em /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ou /home/yunohost.backup/archives subpastas", "backup_output_directory_forbidden": "Escolha um diretório de saída diferente. Backups não podem ser criados nos subdiretórios /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ou /home/yunohost.backup/archives",
"app_already_installed_cant_change_url": "Este aplicativo já está instalado. A URL não pode ser alterada apenas por esta função. Confira em `app changeurl` se está disponível.", "app_already_installed_cant_change_url": "Este aplicativo já está instalado. A URL não pode ser alterada apenas por esta função. Confira em `app changeurl` se está disponível.",
"app_already_up_to_date": "{app} já está atualizado", "app_already_up_to_date": "{app} já está atualizado",
"app_argument_choice_invalid": "Use uma das opções '{choices}' para o argumento '{name}'", "app_argument_choice_invalid": "Use uma das opções '{choices}' para o argumento '{name}' em vez de '{value}'",
"app_argument_invalid": "Escolha um valor válido para o argumento '{name}': {error}", "app_argument_invalid": "Escolha um valor válido para o argumento '{name}': {error}",
"app_argument_required": "O argumento '{name}' é obrigatório", "app_argument_required": "O argumento '{name}' é obrigatório",
"app_change_url_failed_nginx_reload": "Não foi possível reiniciar o nginx. Aqui está o retorno de 'nginx -t':\n{nginx_errors}",
"app_location_unavailable": "Esta url ou não está disponível ou está em conflito com outra(s) aplicação(ões) já instalada(s):\n{apps}", "app_location_unavailable": "Esta url ou não está disponível ou está em conflito com outra(s) aplicação(ões) já instalada(s):\n{apps}",
"app_upgrade_app_name": "Atualizando {app}…", "app_upgrade_app_name": "Atualizando {app}…",
"app_upgrade_some_app_failed": "Não foi possível atualizar algumas aplicações", "app_upgrade_some_app_failed": "Não foi possível atualizar algumas aplicações",
"backup_abstract_method": "Este metodo de backup ainda não foi implementado", "backup_abstract_method": "Este método de backup ainda não foi implementado",
"backup_app_failed": "Não foi possível fazer o backup dos aplicativos '{app}'", "backup_app_failed": "Não foi possível fazer o backup de '{app}'",
"backup_applying_method_custom": "Chamando o metodo personalizado de backup '{method}'…", "backup_applying_method_custom": "Chamando o método personalizado de backup '{method}'…",
"backup_applying_method_tar": "Criando o arquivo tar de backup…", "backup_applying_method_tar": "Criando o arquivo TAR de backup…",
"backup_archive_name_unknown": "Desconhece-se o arquivo local de backup de nome '{name}'", "backup_archive_name_unknown": "Desconhece-se o arquivo local de backup de nome '{name}'",
"backup_archive_system_part_not_available": "A seção do sistema '{part}' está indisponivel neste backup", "backup_archive_system_part_not_available": "A seção do sistema '{part}' está indisponível neste backup",
"backup_ask_for_copying_if_needed": "Alguns arquivos não consiguiram ser preparados para backup utilizando o metodo que não gasta espaço de disco temporariamente. Para realizar o backup {size}MB precisam ser usados temporariamente. Você concorda?", "backup_ask_for_copying_if_needed": "Você quer efetuar o backup usando {size}MB temporariamente? (E necessário fazer dessa forma porque alguns arquivos não puderam ser preparados usando um método mais eficiente)",
"backup_cant_mount_uncompress_archive": "Não foi possível montar em modo leitura o diretorio de arquivos não comprimido", "backup_cant_mount_uncompress_archive": "Não foi possível montar o arquivo descomprimido como protegido contra escrita",
"backup_copying_to_organize_the_archive": "Copiando {size}MB para organizar o arquivo", "backup_copying_to_organize_the_archive": "Copiando {size}MB para organizar o arquivo",
"app_change_url_identical_domains": "O antigo e o novo domínio / url_path são idênticos ('{domain}{path}'), nada para fazer.", "app_change_url_identical_domains": "O antigo e o novo domínio / url_path são idênticos ('{domain}{path}'), nada para fazer.",
"password_too_simple_1": "A senha precisa ter pelo menos 8 caracteres", "password_too_simple_1": "A senha precisa ter pelo menos 8 caracteres",
@ -143,7 +141,7 @@
"app_change_url_success": "A URL agora é {domain}{path}", "app_change_url_success": "A URL agora é {domain}{path}",
"apps_catalog_obsolete_cache": "O cache do catálogo de aplicações está vazio ou obsoleto.", "apps_catalog_obsolete_cache": "O cache do catálogo de aplicações está vazio ou obsoleto.",
"apps_catalog_failed_to_download": "Não foi possível fazer o download do catálogo de aplicações {apps_catalog}: {error}", "apps_catalog_failed_to_download": "Não foi possível fazer o download do catálogo de aplicações {apps_catalog}: {error}",
"apps_catalog_updating": "Atualizado o catálogo de aplicações…", "apps_catalog_updating": "Atualizando o catálogo de aplicações...",
"apps_catalog_init_success": "Catálogo de aplicações do sistema inicializado!", "apps_catalog_init_success": "Catálogo de aplicações do sistema inicializado!",
"apps_already_up_to_date": "Todas as aplicações já estão atualizadas", "apps_already_up_to_date": "Todas as aplicações já estão atualizadas",
"app_packaging_format_not_supported": "Essa aplicação não pode ser instalada porque o formato dela não é suportado pela sua versão do YunoHost. Considere atualizar seu sistema.", "app_packaging_format_not_supported": "Essa aplicação não pode ser instalada porque o formato dela não é suportado pela sua versão do YunoHost. Considere atualizar seu sistema.",
@ -164,5 +162,34 @@
"app_manifest_install_ask_path": "Escolha o caminho da url (depois do domínio) em que essa aplicação deve ser instalada", "app_manifest_install_ask_path": "Escolha o caminho da url (depois do domínio) em que essa aplicação deve ser instalada",
"app_manifest_install_ask_domain": "Escolha o domínio em que esta aplicação deve ser instalada", "app_manifest_install_ask_domain": "Escolha o domínio em que esta aplicação deve ser instalada",
"app_label_deprecated": "Este comando está deprecado! Por favor use o novo comando 'yunohost user permission update' para gerenciar a etiqueta da aplicação.", "app_label_deprecated": "Este comando está deprecado! Por favor use o novo comando 'yunohost user permission update' para gerenciar a etiqueta da aplicação.",
"app_make_default_location_already_used": "Não foi passível fazer a aplicação '{app}' ser a padrão no domínio, '{domain}' já está sendo usado por '{other_app}'" "app_make_default_location_already_used": "Não foi passível fazer a aplicação '{app}' ser a padrão no domínio, '{domain}' já está sendo usado por '{other_app}'",
} "backup_archive_writing_error": "Não foi possível adicionar os arquivos '{source}' (nomeados dentro do arquivo '{dest}') ao backup no arquivo comprimido '{archive}'",
"backup_archive_corrupted": "Parece que o arquivo de backup '{archive}' está corrompido: {error}",
"backup_archive_cant_retrieve_info_json": "Não foi possível carregar informações para o arquivo '{archive}'... Não foi possível carregar info.json (ou não é um JSON válido).",
"backup_applying_method_copy": "Copiando todos os arquivos para o backup...",
"backup_actually_backuping": "Criando cópia de backup dos arquivos obtidos...",
"ask_user_domain": "Domínio para usar para o endereço de email e conta XMPP do usuário",
"ask_new_path": "Novo caminho",
"ask_new_domain": "Novo domínio",
"apps_catalog_update_success": "O catálogo de aplicações foi atualizado!",
"backup_no_uncompress_archive_dir": "Não existe tal diretório de arquivo descomprimido",
"backup_mount_archive_for_restore": "Preparando o arquivo para restauração...",
"backup_method_tar_finished": "Arquivo de backup TAR criado",
"backup_method_custom_finished": "Método de backup personalizado '{method}' finalizado",
"backup_method_copy_finished": "Cópia de backup finalizada",
"backup_custom_mount_error": "O método personalizado de backup não pôde passar do passo de 'mount'",
"backup_custom_backup_error": "O método personalizado de backup não pôde passar do passo de 'backup'",
"backup_csv_creation_failed": "Não foi possível criar o arquivo CSV necessário para a restauração",
"backup_csv_addition_failed": "Não foi possível adicionar os arquivos que estarão no backup ao arquivo CSV",
"backup_create_size_estimation": "O arquivo irá conter cerca de {size} de dados.",
"backup_couldnt_bind": "Não foi possível vincular {src} ao {dest}",
"certmanager_attempt_to_replace_valid_cert": "Você está tentando sobrescrever um certificado bom e válido para o domínio {domain}! (Use --force para prosseguir mesmo assim)",
"backup_with_no_restore_script_for_app": "A aplicação {app} não tem um script de restauração, você não será capaz de automaticamente restaurar o backup dessa aplicação.",
"backup_with_no_backup_script_for_app": "A aplicação '{app}' não tem um script de backup. Ignorando.",
"backup_unable_to_organize_files": "Não foi possível usar o método rápido de organizar os arquivos no arquivo de backup",
"backup_system_part_failed": "Não foi possível fazer o backup da parte do sistema '{part}'",
"backup_running_hooks": "Executando os hooks de backup...",
"backup_permission": "Permissão de backup para {app}",
"backup_output_symlink_dir_broken": "O diretório de seu arquivo '{path}' é um link simbólico quebrado. Talvez você tenha esquecido de re/montar ou conectar o dispositivo de armazenamento para onde o link aponta.",
"backup_output_directory_required": "Você deve especificar um diretório de saída para o backup"
}

View file

@ -13,11 +13,10 @@
"app_change_url_success": "URL-адреса {app} тепер {domain}{path}", "app_change_url_success": "URL-адреса {app} тепер {domain}{path}",
"app_change_url_no_script": "Застосунок '{app_name}' поки не підтримує зміну URL-адрес. Можливо, вам слід оновити його.", "app_change_url_no_script": "Застосунок '{app_name}' поки не підтримує зміну URL-адрес. Можливо, вам слід оновити його.",
"app_change_url_identical_domains": "Старий і новий domain/url_path збігаються ('{domain}{path}'), нічого робити не треба.", "app_change_url_identical_domains": "Старий і новий domain/url_path збігаються ('{domain}{path}'), нічого робити не треба.",
"app_change_url_failed_nginx_reload": "Не вдалося перезавантажити NGINX. Ось результат 'nginx -t':\n{nginx_errors}",
"app_argument_required": "Аргумент '{name}' необхідний", "app_argument_required": "Аргумент '{name}' необхідний",
"app_argument_password_no_default": "Помилка під час розбору аргументу пароля '{name}': аргумент пароля не може мати типове значення з причин безпеки", "app_argument_password_no_default": "Помилка під час розбору аргументу пароля '{name}': аргумент пароля не може мати типове значення з причин безпеки",
"app_argument_invalid": "Виберіть правильне значення для аргументу '{name}': {error}", "app_argument_invalid": "Виберіть правильне значення для аргументу '{name}': {error}",
"app_argument_choice_invalid": "Використовуйте один з цих варіантів '{choices}' для аргументу '{name}'", "app_argument_choice_invalid": "Використовуйте один з цих варіантів '{choices}' для аргументу '{name}' замість '{value}'",
"app_already_up_to_date": "{app} має найостаннішу версію", "app_already_up_to_date": "{app} має найостаннішу версію",
"app_already_installed_cant_change_url": "Цей застосунок уже встановлено. URL-адреса не може бути змінена тільки цією функцією. Перевірте в `app changeurl`, якщо вона доступна.", "app_already_installed_cant_change_url": "Цей застосунок уже встановлено. URL-адреса не може бути змінена тільки цією функцією. Перевірте в `app changeurl`, якщо вона доступна.",
"app_already_installed": "{app} уже встановлено", "app_already_installed": "{app} уже встановлено",
@ -25,9 +24,9 @@
"app_action_cannot_be_ran_because_required_services_down": "Для виконання цієї дії повинні бути запущені наступні необхідні служби: {services}. Спробуйте перезапустити їх, щоб продовжити (і, можливо, з'ясувати, чому вони не працюють).", "app_action_cannot_be_ran_because_required_services_down": "Для виконання цієї дії повинні бути запущені наступні необхідні служби: {services}. Спробуйте перезапустити їх, щоб продовжити (і, можливо, з'ясувати, чому вони не працюють).",
"already_up_to_date": "Нічого не потрібно робити. Все вже актуально.", "already_up_to_date": "Нічого не потрібно робити. Все вже актуально.",
"admin_password_too_long": "Будь ласка, виберіть пароль коротше 127 символів", "admin_password_too_long": "Будь ласка, виберіть пароль коротше 127 символів",
"admin_password_changed": "Пароль адміністратора було змінено", "admin_password_changed": "Пароль адміністрації було змінено",
"admin_password_change_failed": "Неможливо змінити пароль", "admin_password_change_failed": "Неможливо змінити пароль",
"admin_password": "Пароль адміністратора", "admin_password": "Пароль адміністрації",
"additional_urls_already_removed": "Додаткова URL-адреса '{url}' вже видалена в додатковій URL-адресі для дозволу '{permission}'", "additional_urls_already_removed": "Додаткова URL-адреса '{url}' вже видалена в додатковій URL-адресі для дозволу '{permission}'",
"additional_urls_already_added": "Додаткова URL-адреса '{url}' вже додана в додаткову URL-адресу для дозволу '{permission}'", "additional_urls_already_added": "Додаткова URL-адреса '{url}' вже додана в додаткову URL-адресу для дозволу '{permission}'",
"action_invalid": "Неприпустима дія '{action}'", "action_invalid": "Неприпустима дія '{action}'",
@ -87,7 +86,7 @@
"restore_cleaning_failed": "Не вдалося очистити тимчасовий каталог відновлення", "restore_cleaning_failed": "Не вдалося очистити тимчасовий каталог відновлення",
"restore_backup_too_old": "Цей архів резервних копій не може бути відновлений, бо він отриманий з дуже старої версії YunoHost.", "restore_backup_too_old": "Цей архів резервних копій не може бути відновлений, бо він отриманий з дуже старої версії YunoHost.",
"restore_already_installed_apps": "Наступні програми не можуть бути відновлені, тому що вони вже встановлені: {apps}", "restore_already_installed_apps": "Наступні програми не можуть бути відновлені, тому що вони вже встановлені: {apps}",
"restore_already_installed_app": "Застосунок з ID \"{app} 'вже встановлено", "restore_already_installed_app": "Застосунок з ID «{app}» вже встановлено",
"regex_with_only_domain": "Ви не можете використовувати regex для домену, тільки для шляху", "regex_with_only_domain": "Ви не можете використовувати regex для домену, тільки для шляху",
"regex_incompatible_with_tile": "/! \\ Packagers! Дозвіл '{permission}' має значення show_tile 'true', тому ви не можете визначити regex URL в якості основної URL", "regex_incompatible_with_tile": "/! \\ Packagers! Дозвіл '{permission}' має значення show_tile 'true', тому ви не можете визначити regex URL в якості основної URL",
"regenconf_need_to_explicitly_specify_ssh": "Конфігурація ssh була змінена вручну, але вам потрібно явно вказати категорію 'ssh' з --force, щоб застосувати зміни.", "regenconf_need_to_explicitly_specify_ssh": "Конфігурація ssh була змінена вручну, але вам потрібно явно вказати категорію 'ssh' з --force, щоб застосувати зміни.",
@ -127,7 +126,6 @@
"permission_already_allowed": "Група '{group}' вже має увімкнений дозвіл '{permission}'", "permission_already_allowed": "Група '{group}' вже має увімкнений дозвіл '{permission}'",
"pattern_password_app": "На жаль, паролі не можуть містити такі символи: {forbidden_chars}", "pattern_password_app": "На жаль, паролі не можуть містити такі символи: {forbidden_chars}",
"pattern_username": "Має складатися тільки з букв і цифр в нижньому регістрі і символів підкреслення", "pattern_username": "Має складатися тільки з букв і цифр в нижньому регістрі і символів підкреслення",
"pattern_positive_number": "Має бути додатним числом",
"pattern_port_or_range": "Має бути припустимий номер порту (наприклад, 0-65535) або діапазон портів (наприклад, 100:200)", "pattern_port_or_range": "Має бути припустимий номер порту (наприклад, 0-65535) або діапазон портів (наприклад, 100:200)",
"pattern_password": "Має бути довжиною не менше 3 символів", "pattern_password": "Має бути довжиною не менше 3 символів",
"pattern_mailbox_quota": "Має бути розмір з суфіксом b/k/M/G/T або 0, щоб не мати квоти", "pattern_mailbox_quota": "Має бути розмір з суфіксом b/k/M/G/T або 0, щоб не мати квоти",
@ -146,7 +144,7 @@
"operation_interrupted": "Операція була вручну перервана?", "operation_interrupted": "Операція була вручну перервана?",
"invalid_number": "Має бути числом", "invalid_number": "Має бути числом",
"not_enough_disk_space": "Недостатньо вільного місця на '{path}'", "not_enough_disk_space": "Недостатньо вільного місця на '{path}'",
"migrations_to_be_ran_manually": "Міграція {id} повинна бути запущена вручну. Будь ласка, перейдіть в розділ Засоби → Міграції на сторінці вебадміністратора або виконайте команду `yunohost tools migrations run`.", "migrations_to_be_ran_manually": "Міграція {id} повинна бути запущена вручну. Будь ласка, перейдіть в розділ Засоби → Міграції на сторінці вебадміністрації або виконайте команду `yunohost tools migrations run`.",
"migrations_success_forward": "Міграцію {id} завершено", "migrations_success_forward": "Міграцію {id} завершено",
"migrations_skip_migration": "Пропускання міграції {id}...", "migrations_skip_migration": "Пропускання міграції {id}...",
"migrations_running_forward": "Виконання міграції {id}...", "migrations_running_forward": "Виконання міграції {id}...",
@ -175,7 +173,7 @@
"migration_0015_cleaning_up": "Очищення кеш-пам'яті і пакетів, які більше не потрібні...", "migration_0015_cleaning_up": "Очищення кеш-пам'яті і пакетів, які більше не потрібні...",
"migration_0015_specific_upgrade": "Початок оновлення системних пакетів, які повинні бути оновлені незалежно...", "migration_0015_specific_upgrade": "Початок оновлення системних пакетів, які повинні бути оновлені незалежно...",
"migration_0015_modified_files": "Зверніть увагу, що такі файли були змінені вручну і можуть бути перезаписані після оновлення: {manually_modified_files}", "migration_0015_modified_files": "Зверніть увагу, що такі файли були змінені вручну і можуть бути перезаписані після оновлення: {manually_modified_files}",
"migration_0015_problematic_apps_warning": "Зверніть увагу, що були виявлені наступні, можливо, проблемні встановлені застосунки. Схоже, що вони не були встановлені з каталогу застосунків YunoHost або не зазначені як \"робочі\". Отже, не можна гарантувати, що вони будуть працювати після оновлення: {problematic_apps}", "migration_0015_problematic_apps_warning": "Зверніть увагу, що були виявлені наступні, можливо, проблемні встановлені застосунки. Схоже, що вони не були встановлені з каталогу застосунків YunoHost або не зазначені як «робочі». Отже, не можна гарантувати, що вони будуть працювати після оновлення: {problematic_apps}",
"migration_0015_general_warning": "Будь ласка, зверніть увагу, що ця міграція є делікатною операцією. Команда YunoHost зробила все можливе, щоб перевірити і протестувати її, але міграція все ще може порушити частина системи або її застосунків.\n\nТому рекомендовано:\n - Виконати резервне копіювання всіх важливих даних або застосунків. Подробиці на сайті https://yunohost.org/backup; \n - Наберіться терпіння після запуску міграції: В залежності від вашого з'єднання з Інтернетом і апаратного забезпечення, оновлення може зайняти до декількох годин.", "migration_0015_general_warning": "Будь ласка, зверніть увагу, що ця міграція є делікатною операцією. Команда YunoHost зробила все можливе, щоб перевірити і протестувати її, але міграція все ще може порушити частина системи або її застосунків.\n\nТому рекомендовано:\n - Виконати резервне копіювання всіх важливих даних або застосунків. Подробиці на сайті https://yunohost.org/backup; \n - Наберіться терпіння після запуску міграції: В залежності від вашого з'єднання з Інтернетом і апаратного забезпечення, оновлення може зайняти до декількох годин.",
"migration_0015_system_not_fully_up_to_date": "Ваша система не повністю оновлена. Будь ласка, виконайте регулярне оновлення перед запуском міграції на Buster.", "migration_0015_system_not_fully_up_to_date": "Ваша система не повністю оновлена. Будь ласка, виконайте регулярне оновлення перед запуском міграції на Buster.",
"migration_0015_not_enough_free_space": "Вільного місця в /var/ досить мало! У вас повинно бути не менше 1 ГБ вільного місця, щоб запустити цю міграцію.", "migration_0015_not_enough_free_space": "Вільного місця в /var/ досить мало! У вас повинно бути не менше 1 ГБ вільного місця, щоб запустити цю міграцію.",
@ -211,11 +209,11 @@
"log_tools_postinstall": "Післявстановлення сервера YunoHost", "log_tools_postinstall": "Післявстановлення сервера YunoHost",
"log_tools_migrations_migrate_forward": "Запущено міграції", "log_tools_migrations_migrate_forward": "Запущено міграції",
"log_domain_main_domain": "Зроблено '{}' основним доменом", "log_domain_main_domain": "Зроблено '{}' основним доменом",
"log_user_permission_reset": "Скинуто дозвіл \"{} '", "log_user_permission_reset": "Скинуто дозвіл «{}»",
"log_user_permission_update": "Оновлено доступи для дозволу '{}'", "log_user_permission_update": "Оновлено доступи для дозволу '{}'",
"log_user_update": "Оновлено відомості для користувача '{}'", "log_user_update": "Оновлено відомості для користувача '{}'",
"log_user_group_update": "Оновлено групу '{}'", "log_user_group_update": "Оновлено групу '{}'",
"log_user_group_delete": "Видалено групу \"{} '", "log_user_group_delete": "Видалено групу «{}»",
"log_user_group_create": "Створено групу '{}'", "log_user_group_create": "Створено групу '{}'",
"log_user_delete": "Видалення користувача '{}'", "log_user_delete": "Видалення користувача '{}'",
"log_user_create": "Додавання користувача '{}'", "log_user_create": "Додавання користувача '{}'",
@ -236,19 +234,17 @@
"log_backup_restore_system": "Відновлення системи з резервного архіву", "log_backup_restore_system": "Відновлення системи з резервного архіву",
"log_backup_create": "Створення резервного архіву", "log_backup_create": "Створення резервного архіву",
"log_available_on_yunopaste": "Цей журнал тепер доступний за посиланням {url}", "log_available_on_yunopaste": "Цей журнал тепер доступний за посиланням {url}",
"log_app_config_apply": "Застосування конфігурації до застосунку '{}'", "log_app_action_run": "Запуск дії застосунку «{}»",
"log_app_config_show_panel": "Показ панелі конфігурації застосунку '{}'",
"log_app_action_run": "Запуск дії застосунку \"{} '",
"log_app_makedefault": "Застосунок '{}' зроблено типовим", "log_app_makedefault": "Застосунок '{}' зроблено типовим",
"log_app_upgrade": "Оновлення застосунку '{}'", "log_app_upgrade": "Оновлення застосунку '{}'",
"log_app_remove": "Вилучення застосунку '{}'", "log_app_remove": "Вилучення застосунку '{}'",
"log_app_install": "Установлення застосунку '{}'", "log_app_install": "Установлення застосунку '{}'",
"log_app_change_url": "Змінення URL-адреси застосунку \"{} '", "log_app_change_url": "Змінення URL-адреси застосунку «{}»",
"log_operation_unit_unclosed_properly": "Блок операцій не був закритий належним чином", "log_operation_unit_unclosed_properly": "Блок операцій не був закритий належним чином",
"log_does_exists": "Немає журналу операцій з назвою '{log}', використовуйте 'yunohost log list', щоб подивитися всі доступні журнали операцій", "log_does_exists": "Немає журналу операцій з назвою '{log}', використовуйте 'yunohost log list', щоб подивитися всі доступні журнали операцій",
"log_help_to_get_failed_log": "Операція '{desc}' не може бути завершена. Будь ласка, поділіться повним журналом цієї операції, використовуючи команду 'yunohost log share {name}', щоб отримати допомогу", "log_help_to_get_failed_log": "Операція '{desc}' не може бути завершена. Будь ласка, поділіться повним журналом цієї операції, використовуючи команду 'yunohost log share {name}', щоб отримати допомогу",
"log_link_to_failed_log": "Не вдалося завершити операцію '{desc}'. Будь ласка, надайте повний журнал цієї операції, <a href=\"#/tools/logs/{name}\">натиснувши тут</a>, щоб отримати допомогу", "log_link_to_failed_log": "Не вдалося завершити операцію '{desc}'. Будь ласка, надайте повний журнал цієї операції, <a href=\"#/tools/logs/{name}\">натиснувши тут</a>, щоб отримати допомогу",
"log_help_to_get_log": "Щоб переглянути журнал операції '{desc}', використовуйте команду 'yunohost log show {name}{name}'", "log_help_to_get_log": "Щоб переглянути журнал операції '{desc}', використовуйте команду 'yunohost log show {name}'",
"log_link_to_log": "Повний журнал цієї операції: '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>'", "log_link_to_log": "Повний журнал цієї операції: '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>'",
"log_corrupted_md_file": "Файл метаданих YAML, пов'язаний з журналами, пошкоджено: '{md_file}\nПомилка: {error}'", "log_corrupted_md_file": "Файл метаданих YAML, пов'язаний з журналами, пошкоджено: '{md_file}\nПомилка: {error}'",
"iptables_unavailable": "Ви не можете грати з iptables тут. Ви перебуваєте або в контейнері, або ваше ядро не підтримує його", "iptables_unavailable": "Ви не можете грати з iptables тут. Ви перебуваєте або в контейнері, або ваше ядро не підтримує його",
@ -277,11 +273,11 @@
"group_already_exist_on_system": "Група {group} вже існує в групах системи", "group_already_exist_on_system": "Група {group} вже існує в групах системи",
"group_already_exist": "Група {group} вже існує", "group_already_exist": "Група {group} вже існує",
"good_practices_about_user_password": "Зараз ви збираєтеся поставити новий пароль користувача. Пароль повинен складатися не менше ніж з 8 символів, але хорошою практикою є використання більш довгого пароля (тобто гасла) і/або використання різних символів (великих, малих, цифр і спеціальних символів).", "good_practices_about_user_password": "Зараз ви збираєтеся поставити новий пароль користувача. Пароль повинен складатися не менше ніж з 8 символів, але хорошою практикою є використання більш довгого пароля (тобто гасла) і/або використання різних символів (великих, малих, цифр і спеціальних символів).",
"good_practices_about_admin_password": "Зараз ви збираєтеся поставити новий пароль адміністратора. Пароль повинен складатися не менше ніж з 8 символів, але хорошою практикою є використання більш довгого пароля (тобто парольного гасла) і/або використання різних символів (великих, малих, цифр і спеціальних символів).", "good_practices_about_admin_password": "Зараз ви збираєтеся поставити новий пароль адміністрації. Пароль повинен складатися не менше ніж з 8 символів, але хорошою практикою є використання більш довгого пароля (тобто парольного гасла) і/або використання різних символів (великих, малих, цифр і спеціальних символів).",
"global_settings_unknown_type": "Несподівана ситуація, налаштування {setting} має тип {unknown_type}, але це не тип, підтримуваний системою.", "global_settings_unknown_type": "Несподівана ситуація, налаштування {setting} має тип {unknown_type}, але це не тип, підтримуваний системою.",
"global_settings_setting_backup_compress_tar_archives": "При створенні нових резервних копій стискати архіви (.tar.gz) замість нестислих архівів (.tar). NB: вмикання цієї опції означає створення легших архівів резервних копій, але початкова процедура резервного копіювання буде значно довшою і важчою для CPU.", "global_settings_setting_backup_compress_tar_archives": "При створенні нових резервних копій стискати архіви (.tar.gz) замість нестислих архівів (.tar). NB: вмикання цієї опції означає створення легших архівів резервних копій, але початкова процедура резервного копіювання буде значно довшою і важчою для CPU.",
"global_settings_setting_security_webadmin_allowlist": "IP-адреси, яким дозволений доступ до вебадміністратора. Через кому.", "global_settings_setting_security_webadmin_allowlist": "IP-адреси, яким дозволений доступ до вебадміністрації. Через кому.",
"global_settings_setting_security_webadmin_allowlist_enabled": "Дозволити доступ до вебадміністратора тільки деяким IP-адресам.", "global_settings_setting_security_webadmin_allowlist_enabled": "Дозволити доступ до вебадміністрації тільки деяким IP-адресам.",
"global_settings_setting_smtp_relay_password": "Пароль хоста SMTP-ретрансляції", "global_settings_setting_smtp_relay_password": "Пароль хоста SMTP-ретрансляції",
"global_settings_setting_smtp_relay_user": "Обліковий запис користувача SMTP-ретрансляції", "global_settings_setting_smtp_relay_user": "Обліковий запис користувача SMTP-ретрансляції",
"global_settings_setting_smtp_relay_port": "Порт SMTP-ретрансляції", "global_settings_setting_smtp_relay_port": "Порт SMTP-ретрансляції",
@ -328,7 +324,6 @@
"downloading": "Завантаження…", "downloading": "Завантаження…",
"done": "Готово", "done": "Готово",
"domains_available": "Доступні домени:", "domains_available": "Доступні домени:",
"domain_unknown": "Невідомий домен",
"domain_name_unknown": "Домен '{domain}' невідомий", "domain_name_unknown": "Домен '{domain}' невідомий",
"domain_uninstall_app_first": "Ці застосунки все ще встановлені на вашому домені:\n{apps}\n\nВидаліть їх за допомогою 'yunohost app remove the_app_id' або перемістіть їх на інший домен за допомогою 'yunohost app change-url the_app_id', перш ніж приступити до вилучення домену", "domain_uninstall_app_first": "Ці застосунки все ще встановлені на вашому домені:\n{apps}\n\nВидаліть їх за допомогою 'yunohost app remove the_app_id' або перемістіть їх на інший домен за допомогою 'yunohost app change-url the_app_id', перш ніж приступити до вилучення домену",
"domain_remove_confirm_apps_removal": "Вилучення цього домену призведе до вилучення таких застосунків:\n{apps}\n\nВи впевнені, що хочете це зробити? [{answers}]", "domain_remove_confirm_apps_removal": "Вилучення цього домену призведе до вилучення таких застосунків:\n{apps}\n\nВи впевнені, що хочете це зробити? [{answers}]",
@ -351,7 +346,7 @@
"diagnosis_sshd_config_inconsistent": "Схоже, що порт SSH був уручну змінений в /etc/ssh/sshd_config. Починаючи з версії YunoHost 4.2, доступний новий глобальний параметр 'security.ssh.port', що дозволяє уникнути ручного редагування конфігурації.", "diagnosis_sshd_config_inconsistent": "Схоже, що порт SSH був уручну змінений в /etc/ssh/sshd_config. Починаючи з версії YunoHost 4.2, доступний новий глобальний параметр 'security.ssh.port', що дозволяє уникнути ручного редагування конфігурації.",
"diagnosis_sshd_config_insecure": "Схоже, що конфігурація SSH була змінена вручну і є небезпечною, оскільки не містить директив 'AllowGroups' або 'AllowUsers' для обмеження доступу авторизованих користувачів.", "diagnosis_sshd_config_insecure": "Схоже, що конфігурація SSH була змінена вручну і є небезпечною, оскільки не містить директив 'AllowGroups' або 'AllowUsers' для обмеження доступу авторизованих користувачів.",
"diagnosis_processes_killed_by_oom_reaper": "Деякі процеси було недавно вбито системою через брак пам'яті. Зазвичай це є симптомом нестачі пам'яті в системі або процесу, який з'їв дуже багато пам'яті. Зведення убитих процесів:\n{kills_summary}", "diagnosis_processes_killed_by_oom_reaper": "Деякі процеси було недавно вбито системою через брак пам'яті. Зазвичай це є симптомом нестачі пам'яті в системі або процесу, який з'їв дуже багато пам'яті. Зведення убитих процесів:\n{kills_summary}",
"diagnosis_never_ran_yet": "Схоже, що цей сервер був налаштований недавно, і поки немає звіту про діагностику. Вам слід почати з повної діагностики, або з вебадміністратора, або використовуючи 'yunohost diagnosis run' з командного рядка.", "diagnosis_never_ran_yet": "Схоже, що цей сервер був налаштований недавно, і поки немає звіту про діагностику. Вам слід почати з повної діагностики, або з вебадміністрації, або використовуючи 'yunohost diagnosis run' з командного рядка.",
"diagnosis_unknown_categories": "Наступні категорії невідомі: {categories}", "diagnosis_unknown_categories": "Наступні категорії невідомі: {categories}",
"diagnosis_http_nginx_conf_not_up_to_date_details": "Щоб виправити становище, перевірте різницю за допомогою командного рядка, використовуючи <cmd>yunohost tools regen-conf nginx --dry-run --with-diff</cmd>, і якщо все в порядку, застосуйте зміни за допомогою команди <cmd>yunohost tools regen-conf nginx --force</cmd>.", "diagnosis_http_nginx_conf_not_up_to_date_details": "Щоб виправити становище, перевірте різницю за допомогою командного рядка, використовуючи <cmd>yunohost tools regen-conf nginx --dry-run --with-diff</cmd>, і якщо все в порядку, застосуйте зміни за допомогою команди <cmd>yunohost tools regen-conf nginx --force</cmd>.",
"diagnosis_http_nginx_conf_not_up_to_date": "Схоже, що конфігурація nginx цього домену була змінена вручну, що не дозволяє YunoHost визначити, чи доступний він по HTTP.", "diagnosis_http_nginx_conf_not_up_to_date": "Схоже, що конфігурація nginx цього домену була змінена вручну, що не дозволяє YunoHost визначити, чи доступний він по HTTP.",
@ -416,7 +411,7 @@
"diagnosis_mail_outgoing_port_25_blocked_details": "Спочатку спробуйте розблокувати вихідний порт 25 в інтерфейсі вашого інтернет-маршрутизатора або в інтерфейсі вашого хостинг-провайдера. (Деякі хостинг-провайдери можуть вимагати, щоб ви відправили їм заявку в службу підтримки).", "diagnosis_mail_outgoing_port_25_blocked_details": "Спочатку спробуйте розблокувати вихідний порт 25 в інтерфейсі вашого інтернет-маршрутизатора або в інтерфейсі вашого хостинг-провайдера. (Деякі хостинг-провайдери можуть вимагати, щоб ви відправили їм заявку в службу підтримки).",
"diagnosis_mail_outgoing_port_25_blocked": "Поштовий сервер SMTP не може відправляти електронні листи на інші сервери, оскільки вихідний порт 25 заблоковано в IPv{ipversion}.", "diagnosis_mail_outgoing_port_25_blocked": "Поштовий сервер SMTP не може відправляти електронні листи на інші сервери, оскільки вихідний порт 25 заблоковано в IPv{ipversion}.",
"app_manifest_install_ask_path": "Оберіть шлях URL (після домену), за яким має бути встановлено цей застосунок", "app_manifest_install_ask_path": "Оберіть шлях URL (після домену), за яким має бути встановлено цей застосунок",
"yunohost_postinstall_end_tip": "Післявстановлення завершено! Щоб завершити доналаштування, будь ласка, розгляньте наступні варіанти:\n - додавання першого користувача через розділ 'Користувачі' вебадміністратора (або 'yunohost user create <username>' в командному рядку);\n - діагностика можливих проблем через розділ 'Діагностика' вебадміністратора (або 'yunohost diagnosis run' в командному рядку);\n - прочитання розділів 'Завершення встановлення' і 'Знайомство з YunoHost' у документації адміністратора: https://yunohost.org/admindoc.", "yunohost_postinstall_end_tip": "Післявстановлення завершено! Щоб завершити доналаштування, будь ласка, розгляньте наступні варіанти:\n - додавання першого користувача через розділ 'Користувачі' вебадміністрації (або 'yunohost user create <username>' в командному рядку);\n - діагностика можливих проблем через розділ 'Діагностика' вебадміністрації (або 'yunohost diagnosis run' в командному рядку);\n - прочитання розділів 'Завершення встановлення' і 'Знайомство з YunoHost' у документації адміністратора: https://yunohost.org/admindoc.",
"yunohost_not_installed": "YunoHost установлений неправильно. Будь ласка, запустіть 'yunohost tools postinstall'", "yunohost_not_installed": "YunoHost установлений неправильно. Будь ласка, запустіть 'yunohost tools postinstall'",
"yunohost_installing": "Установлення YunoHost...", "yunohost_installing": "Установлення YunoHost...",
"yunohost_configured": "YunoHost вже налаштовано", "yunohost_configured": "YunoHost вже налаштовано",
@ -445,7 +440,7 @@
"unexpected_error": "Щось пішло не так: {error}", "unexpected_error": "Щось пішло не так: {error}",
"unbackup_app": "{app} НЕ буде збережено", "unbackup_app": "{app} НЕ буде збережено",
"tools_upgrade_special_packages_completed": "Оновлення пакета YunoHost завершено.\nНатисніть [Enter] для повернення до командного рядка", "tools_upgrade_special_packages_completed": "Оновлення пакета YunoHost завершено.\nНатисніть [Enter] для повернення до командного рядка",
"tools_upgrade_special_packages_explanation": "Спеціальне оновлення триватиме у тлі. Будь ласка, не запускайте ніяких інших дій на вашому сервері протягом наступних ~ 10 хвилин (в залежності від швидкості обладнання). Після цього вам, можливо, доведеться заново увійти в вебадміністратора. Журнал оновлення буде доступний в Засоби → Журнал (в веб-адміністраторі) або за допомогою 'yunohost log list' (з командного рядка).", "tools_upgrade_special_packages_explanation": "Спеціальне оновлення триватиме у тлі. Будь ласка, не запускайте ніяких інших дій на вашому сервері протягом наступних ~ 10 хвилин (в залежності від швидкості обладнання). Після цього вам, можливо, доведеться заново увійти в вебадміністрації. Журнал оновлення буде доступний в Засоби → Журнал (в вебадміністрації) або за допомогою 'yunohost log list' (з командного рядка).",
"tools_upgrade_special_packages": "Тепер оновлюємо 'спеціальні' (пов'язані з yunohost) пакети…", "tools_upgrade_special_packages": "Тепер оновлюємо 'спеціальні' (пов'язані з yunohost) пакети…",
"tools_upgrade_regular_packages_failed": "Не вдалося оновити пакети: {packages_list}", "tools_upgrade_regular_packages_failed": "Не вдалося оновити пакети: {packages_list}",
"tools_upgrade_regular_packages": "Тепер оновлюємо 'звичайні' (не пов'язані з yunohost) пакети…", "tools_upgrade_regular_packages": "Тепер оновлюємо 'звичайні' (не пов'язані з yunohost) пакети…",
@ -476,7 +471,7 @@
"diagnosis_diskusage_ok": "У сховищі <code>{mountpoint}</code> (на пристрої <code>{device}</code>) залишилося {free} ({free_percent}%) вільного місця (з {total})!", "diagnosis_diskusage_ok": "У сховищі <code>{mountpoint}</code> (на пристрої <code>{device}</code>) залишилося {free} ({free_percent}%) вільного місця (з {total})!",
"diagnosis_diskusage_low": "Сховище <code>{mountpoint}</code> (на пристрої <code>{device}</code>) має тільки {free} ({free_percent}%) вільного місця (з {total}). Будьте уважні.", "diagnosis_diskusage_low": "Сховище <code>{mountpoint}</code> (на пристрої <code>{device}</code>) має тільки {free} ({free_percent}%) вільного місця (з {total}). Будьте уважні.",
"diagnosis_diskusage_verylow": "Сховище <code>{mountpoint}</code> (на пристрої <code>{device}</code>) має тільки {free} ({free_percent}%) вільного місця (з {total}). Вам дійсно варто подумати про очищення простору!", "diagnosis_diskusage_verylow": "Сховище <code>{mountpoint}</code> (на пристрої <code>{device}</code>) має тільки {free} ({free_percent}%) вільного місця (з {total}). Вам дійсно варто подумати про очищення простору!",
"diagnosis_services_bad_status_tip": "Ви можете спробувати <a href='#/services/{service}'>перезапустити службу</a>, а якщо це не допоможе, подивіться <a href='#/services/{service}'>журнали служби в вебадміністраторі </a> (з командного рядка це можна зробити за допомогою <cmd>yunohost service restart {service}</cmd> і <cmd>yunohost service log {service}</cmd>).", "diagnosis_services_bad_status_tip": "Ви можете спробувати <a href='#/services/{service}'>перезапустити службу</a>, а якщо це не допоможе, подивіться <a href='#/services/{service}'>журнали служби в вебадміністрації </a> (з командного рядка це можна зробити за допомогою <cmd>yunohost service restart {service}</cmd> і <cmd>yunohost service log {service}</cmd>).",
"diagnosis_services_bad_status": "Служба {service} у стані {status} :(", "diagnosis_services_bad_status": "Служба {service} у стані {status} :(",
"diagnosis_services_conf_broken": "Для служби {service} порушена конфігурація!", "diagnosis_services_conf_broken": "Для служби {service} порушена конфігурація!",
"diagnosis_services_running": "Службу {service} запущено!", "diagnosis_services_running": "Службу {service} запущено!",
@ -507,7 +502,7 @@
"diagnosis_ip_connected_ipv6": "Сервер під'єднаний до Інтернету через IPv6!", "diagnosis_ip_connected_ipv6": "Сервер під'єднаний до Інтернету через IPv6!",
"diagnosis_ip_no_ipv4": "Сервер не має робочого IPv4.", "diagnosis_ip_no_ipv4": "Сервер не має робочого IPv4.",
"diagnosis_ip_connected_ipv4": "Сервер під'єднаний до Інтернету через IPv4!", "diagnosis_ip_connected_ipv4": "Сервер під'єднаний до Інтернету через IPv4!",
"diagnosis_no_cache": "Для категорії \"{category} 'ще немає кеша діагностики", "diagnosis_no_cache": "Для категорії «{category}» ще немає кеша діагностики",
"diagnosis_failed": "Не вдалося отримати результат діагностики для категорії '{category}': {error}", "diagnosis_failed": "Не вдалося отримати результат діагностики для категорії '{category}': {error}",
"diagnosis_everything_ok": "Усе виглядає добре для {category}!", "diagnosis_everything_ok": "Усе виглядає добре для {category}!",
"diagnosis_found_warnings": "Знайдено {warnings} пунктів, які можна поліпшити для {category}.", "diagnosis_found_warnings": "Знайдено {warnings} пунктів, які можна поліпшити для {category}.",
@ -517,7 +512,7 @@
"diagnosis_cant_run_because_of_dep": "Неможливо запустити діагностику для {category}, поки є важливі проблеми, пов'язані з {dep}.", "diagnosis_cant_run_because_of_dep": "Неможливо запустити діагностику для {category}, поки є важливі проблеми, пов'язані з {dep}.",
"diagnosis_cache_still_valid": "(Кеш все ще дійсний для діагностики {category}. Повторна діагностика поки не проводиться!)", "diagnosis_cache_still_valid": "(Кеш все ще дійсний для діагностики {category}. Повторна діагностика поки не проводиться!)",
"diagnosis_failed_for_category": "Не вдалося провести діагностику для категорії '{category}': {error}", "diagnosis_failed_for_category": "Не вдалося провести діагностику для категорії '{category}': {error}",
"diagnosis_display_tip": "Щоб побачити знайдені проблеми, ви можете перейти в розділ Діагностика в вебадміністраторі або виконати команду 'yunohost diagnosis show --issues --human-readable' з командного рядка.", "diagnosis_display_tip": "Щоб побачити знайдені проблеми, ви можете перейти в розділ Діагностика в вебадміністрації або виконати команду 'yunohost diagnosis show --issues --human-readable' з командного рядка.",
"diagnosis_package_installed_from_sury_details": "Деякі пакети були ненавмисно встановлені зі стороннього репозиторію під назвою Sury. Команда YunoHost поліпшила стратегію роботи з цими пакетами, але очікується, що в деяких системах, які встановили застосунки PHP7.3 ще на Stretch, залишаться деякі невідповідності. Щоб виправити це становище, спробуйте виконати наступну команду: <cmd>{cmd_to_fix}</cmd>", "diagnosis_package_installed_from_sury_details": "Деякі пакети були ненавмисно встановлені зі стороннього репозиторію під назвою Sury. Команда YunoHost поліпшила стратегію роботи з цими пакетами, але очікується, що в деяких системах, які встановили застосунки PHP7.3 ще на Stretch, залишаться деякі невідповідності. Щоб виправити це становище, спробуйте виконати наступну команду: <cmd>{cmd_to_fix}</cmd>",
"diagnosis_package_installed_from_sury": "Деякі системні пакети мають бути зістарені у версії", "diagnosis_package_installed_from_sury": "Деякі системні пакети мають бути зістарені у версії",
"diagnosis_backports_in_sources_list": "Схоже, що apt (менеджер пакетів) налаштований на використання репозиторія backports. Якщо ви не знаєте, що робите, ми наполегливо не радимо встановлювати пакети з backports, тому що це може привести до нестабільності або конфліктів у вашій системі.", "diagnosis_backports_in_sources_list": "Схоже, що apt (менеджер пакетів) налаштований на використання репозиторія backports. Якщо ви не знаєте, що робите, ми наполегливо не радимо встановлювати пакети з backports, тому що це може привести до нестабільності або конфліктів у вашій системі.",
@ -600,7 +595,7 @@
"ask_password": "Пароль", "ask_password": "Пароль",
"ask_new_path": "Новий шлях", "ask_new_path": "Новий шлях",
"ask_new_domain": "Новий домен", "ask_new_domain": "Новий домен",
"ask_new_admin_password": "Новий пароль адміністратора", "ask_new_admin_password": "Новий пароль адміністрації",
"ask_main_domain": "Основний домен", "ask_main_domain": "Основний домен",
"ask_lastname": "Прізвище", "ask_lastname": "Прізвище",
"ask_firstname": "Ім'я", "ask_firstname": "Ім'я",
@ -637,7 +632,7 @@
"app_not_upgraded": "Застосунок '{failed_app}' не вдалося оновити, і, як наслідок, оновлення таких застосунків було скасовано: {apps}", "app_not_upgraded": "Застосунок '{failed_app}' не вдалося оновити, і, як наслідок, оновлення таких застосунків було скасовано: {apps}",
"app_manifest_install_ask_is_public": "Чи має цей застосунок бути відкритим для анонімних відвідувачів?", "app_manifest_install_ask_is_public": "Чи має цей застосунок бути відкритим для анонімних відвідувачів?",
"app_manifest_install_ask_admin": "Виберіть користувача-адміністратора для цього застосунку", "app_manifest_install_ask_admin": "Виберіть користувача-адміністратора для цього застосунку",
"app_manifest_install_ask_password": "Виберіть пароль адміністратора для цього застосунку", "app_manifest_install_ask_password": "Виберіть пароль адміністрації для цього застосунку",
"diagnosis_description_apps": "Застосунки", "diagnosis_description_apps": "Застосунки",
"user_import_success": "Користувачів успішно імпортовано", "user_import_success": "Користувачів успішно імпортовано",
"user_import_nothing_to_do": "Не потрібно імпортувати жодного користувача", "user_import_nothing_to_do": "Не потрібно імпортувати жодного користувача",
@ -657,5 +652,28 @@
"diagnosis_apps_broken": "Цей застосунок наразі позначено як зламаний у каталозі застосунків YunoHost. Це може бути тимчасовою проблемою, поки організатори намагаються вирішити цю проблему. Тим часом оновлення цього застосунку вимкнено.", "diagnosis_apps_broken": "Цей застосунок наразі позначено як зламаний у каталозі застосунків YunoHost. Це може бути тимчасовою проблемою, поки організатори намагаються вирішити цю проблему. Тим часом оновлення цього застосунку вимкнено.",
"diagnosis_apps_not_in_app_catalog": "Цей застосунок не міститься у каталозі застосунків YunoHost. Якщо він був у минулому і був видалений, вам слід подумати про видалення цього застосунку, оскільки він не отримає оновлення, і це може поставити під загрозу цілісність та безпеку вашої системи.", "diagnosis_apps_not_in_app_catalog": "Цей застосунок не міститься у каталозі застосунків YunoHost. Якщо він був у минулому і був видалений, вам слід подумати про видалення цього застосунку, оскільки він не отримає оновлення, і це може поставити під загрозу цілісність та безпеку вашої системи.",
"diagnosis_apps_issue": "Виявлено проблему із застосунком {app}", "diagnosis_apps_issue": "Виявлено проблему із застосунком {app}",
"diagnosis_apps_allgood": "Усі встановлені застосунки дотримуються основних способів упакування" "diagnosis_apps_allgood": "Усі встановлені застосунки дотримуються основних способів упакування",
} "diagnosis_high_number_auth_failures": "Останнім часом сталася підозріло велика кількість помилок автентифікації. Ви можете переконатися, що fail2ban працює і правильно налаштований, або скористатися власним портом для SSH, як описано в https://yunohost.org/security.",
"global_settings_setting_security_nginx_redirect_to_https": "Типово переспрямовувати HTTP-запити до HTTP (НЕ ВИМИКАЙТЕ, якщо ви дійсно не знаєте, що робите!)",
"app_config_unable_to_apply": "Не вдалося застосувати значення панелі конфігурації.",
"app_config_unable_to_read": "Не вдалося розпізнати значення панелі конфігурації.",
"config_apply_failed": "Не вдалося застосувати нову конфігурацію: {error}",
"config_cant_set_value_on_section": "Ви не можете встановити одне значення на весь розділ конфігурації.",
"config_forbidden_keyword": "Ключове слово '{keyword}' зарезервовано, ви не можете створити або використовувати панель конфігурації з запитом із таким ID.",
"config_no_panel": "Панель конфігурації не знайдено.",
"config_unknown_filter_key": "Ключ фільтра '{filter_key}' недійсний.",
"config_validate_color": "Колір RGB має бути дійсним шістнадцятковим кольоровим кодом",
"config_validate_date": "Дата має бути дійсною, наприклад, у форматі РРРР-ММ-ДД",
"config_validate_email": "Е-пошта має бути дійсною",
"config_validate_time": "Час має бути дійсним, наприклад ГГ:ХХ",
"config_validate_url": "Вебадреса має бути дійсною",
"config_version_not_supported": "Версії конфігураційної панелі '{version}' не підтримуються.",
"danger": "Небезпека:",
"file_extension_not_accepted": "Файл '{path}' відхиляється, бо його розширення не входить в число прийнятих розширень: {accept}",
"invalid_number_min": "Має бути більшим за {min}",
"invalid_number_max": "Має бути меншим за {max}",
"log_app_config_set": "Застосувати конфігурацію до застосунку '{}'",
"service_not_reloading_because_conf_broken": "Неможливо перезавантажити/перезапустити службу '{name}', тому що її конфігурацію порушено: {errors}",
"app_argument_password_help_optional": "Введіть один пробіл, щоб очистити пароль",
"app_argument_password_help_keep": "Натисніть Enter, щоб зберегти поточне значення"
}

View file

@ -150,7 +150,6 @@
"app_change_url_success": "{app} URL现在为 {domain}{path}", "app_change_url_success": "{app} URL现在为 {domain}{path}",
"app_change_url_no_script": "应用程序'{app_name}'尚不支持URL修改. 也许您应该升级它。", "app_change_url_no_script": "应用程序'{app_name}'尚不支持URL修改. 也许您应该升级它。",
"app_change_url_identical_domains": "新旧domain / url_path是相同的('{domain}{path}'),无需执行任何操作。", "app_change_url_identical_domains": "新旧domain / url_path是相同的('{domain}{path}'),无需执行任何操作。",
"app_change_url_failed_nginx_reload": "无法重新加载NGINX. 这是'nginx -t'的输出:\n{nginx_errors}",
"app_argument_required": "参数'{name}'为必填项", "app_argument_required": "参数'{name}'为必填项",
"app_argument_password_no_default": "解析密码参数'{name}'时出错:出于安全原因,密码参数不能具有默认值", "app_argument_password_no_default": "解析密码参数'{name}'时出错:出于安全原因,密码参数不能具有默认值",
"app_argument_invalid": "为参数'{name}'选择一个有效值: {error}", "app_argument_invalid": "为参数'{name}'选择一个有效值: {error}",
@ -360,7 +359,6 @@
"downloading": "下载中…", "downloading": "下载中…",
"done": "完成", "done": "完成",
"domains_available": "可用域:", "domains_available": "可用域:",
"domain_unknown": "未知网域",
"domain_name_unknown": "域'{domain}'未知", "domain_name_unknown": "域'{domain}'未知",
"domain_uninstall_app_first": "这些应用程序仍安装在您的域中:\n{apps}\n\n请先使用 'yunohost app remove the_app_id' 将其卸载,或使用 'yunohost app change-url the_app_id'将其移至另一个域,然后再继续删除域", "domain_uninstall_app_first": "这些应用程序仍安装在您的域中:\n{apps}\n\n请先使用 'yunohost app remove the_app_id' 将其卸载,或使用 'yunohost app change-url the_app_id'将其移至另一个域,然后再继续删除域",
"domain_remove_confirm_apps_removal": "删除该域将删除这些应用程序:\n{apps}\n\n您确定要这样做吗? [{answers}]", "domain_remove_confirm_apps_removal": "删除该域将删除这些应用程序:\n{apps}\n\n您确定要这样做吗? [{answers}]",
@ -499,8 +497,6 @@
"diagnosis_dns_discrepancy": "以下DNS记录似乎未遵循建议的配置:<br>类型: <code>{type}</code><br>名称: <code>{name}</code><br>代码> 当前值: <code>{current}期望值: <code>{value}</code>", "diagnosis_dns_discrepancy": "以下DNS记录似乎未遵循建议的配置:<br>类型: <code>{type}</code><br>名称: <code>{name}</code><br>代码> 当前值: <code>{current}期望值: <code>{value}</code>",
"log_backup_create": "创建备份档案", "log_backup_create": "创建备份档案",
"log_available_on_yunopaste": "现在可以通过{url}使用此日志", "log_available_on_yunopaste": "现在可以通过{url}使用此日志",
"log_app_config_apply": "将配置应用于 '{}' 应用",
"log_app_config_show_panel": "显示 '{}' 应用的配置面板",
"log_app_action_run": "运行 '{}' 应用的操作", "log_app_action_run": "运行 '{}' 应用的操作",
"log_app_makedefault": "将 '{}' 设为默认应用", "log_app_makedefault": "将 '{}' 设为默认应用",
"log_app_upgrade": "升级 '{}' 应用", "log_app_upgrade": "升级 '{}' 应用",
@ -511,7 +507,7 @@
"log_does_exists": "没有名称为'{log}'的操作日志,请使用 'yunohost log list' 查看所有可用的操作日志", "log_does_exists": "没有名称为'{log}'的操作日志,请使用 'yunohost log list' 查看所有可用的操作日志",
"log_help_to_get_failed_log": "操作'{desc}'无法完成。请使用命令'yunohost log share {name}' 共享此操作的完整日志以获取帮助", "log_help_to_get_failed_log": "操作'{desc}'无法完成。请使用命令'yunohost log share {name}' 共享此操作的完整日志以获取帮助",
"log_link_to_failed_log": "无法完成操作 '{desc}'。请通过<a href=\"#/tools/logs/{name}\">单击此处</a>提供此操作的完整日志以获取帮助", "log_link_to_failed_log": "无法完成操作 '{desc}'。请通过<a href=\"#/tools/logs/{name}\">单击此处</a>提供此操作的完整日志以获取帮助",
"log_help_to_get_log": "要查看操作'{desc}'的日志,请使用命令'yunohost log show {name}{name}'", "log_help_to_get_log": "要查看操作'{desc}'的日志,请使用命令'yunohost log show {name}'",
"log_link_to_log": "此操作的完整日志: '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>'", "log_link_to_log": "此操作的完整日志: '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>'",
"log_corrupted_md_file": "与日志关联的YAML元数据文件已损坏: '{md_file}\n错误: {error}'", "log_corrupted_md_file": "与日志关联的YAML元数据文件已损坏: '{md_file}\n错误: {error}'",
"iptables_unavailable": "你不能在这里使用iptables。你要么在一个容器中要么你的内核不支持它", "iptables_unavailable": "你不能在这里使用iptables。你要么在一个容器中要么你的内核不支持它",
@ -541,7 +537,6 @@
"permission_already_allowed": "群组 '{group}' 已启用权限'{permission}'", "permission_already_allowed": "群组 '{group}' 已启用权限'{permission}'",
"pattern_password_app": "抱歉,密码不能包含以下字符: {forbidden_chars}", "pattern_password_app": "抱歉,密码不能包含以下字符: {forbidden_chars}",
"pattern_username": "只能为小写字母数字和下划线字符", "pattern_username": "只能为小写字母数字和下划线字符",
"pattern_positive_number": "必须为正数",
"pattern_port_or_range": "必须是有效的端口号即0-65535或端口范围例如100:200", "pattern_port_or_range": "必须是有效的端口号即0-65535或端口范围例如100:200",
"pattern_password": "必须至少3个字符长", "pattern_password": "必须至少3个字符长",
"pattern_mailbox_quota": "必须为带b/k/M/G/T 后缀的大小或0才能没有配额", "pattern_mailbox_quota": "必须为带b/k/M/G/T 后缀的大小或0才能没有配额",

2
src/yunohost/.coveragerc Normal file
View file

@ -0,0 +1,2 @@
[report]
omit=tests/*,vendor/*,/usr/lib/moulinette/yunohost/

File diff suppressed because it is too large Load diff

View file

@ -44,11 +44,11 @@ from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import read_file, mkdir, write_to_yaml, read_yaml from moulinette.utils.filesystem import read_file, mkdir, write_to_yaml, read_yaml
from moulinette.utils.process import check_output from moulinette.utils.process import check_output
import yunohost.domain
from yunohost.app import ( from yunohost.app import (
app_info, app_info,
_is_installed, _is_installed,
_make_environment_for_app_script, _make_environment_for_app_script,
dump_app_log_extract_for_debugging,
_patch_legacy_helpers, _patch_legacy_helpers,
_patch_legacy_php_versions, _patch_legacy_php_versions,
_patch_legacy_php_versions_in_settings, _patch_legacy_php_versions_in_settings,
@ -60,6 +60,7 @@ from yunohost.hook import (
hook_info, hook_info,
hook_callback, hook_callback,
hook_exec, hook_exec,
hook_exec_with_script_debug_if_failure,
CUSTOM_HOOK_FOLDER, CUSTOM_HOOK_FOLDER,
) )
from yunohost.tools import ( from yunohost.tools import (
@ -707,6 +708,9 @@ class BackupManager:
# Prepare environment # Prepare environment
env_dict = self._get_env_var(app) env_dict = self._get_env_var(app)
env_dict["YNH_APP_BASEDIR"] = os.path.join(
self.work_dir, "apps", app, "settings"
)
tmp_app_bkp_dir = env_dict["YNH_APP_BACKUP_DIR"] tmp_app_bkp_dir = env_dict["YNH_APP_BACKUP_DIR"]
settings_dir = os.path.join(self.work_dir, "apps", app, "settings") settings_dir = os.path.join(self.work_dir, "apps", app, "settings")
@ -1287,6 +1291,8 @@ class RestoreManager:
else: else:
operation_logger.success() operation_logger.success()
yunohost.domain.domain_list_cache = {}
regen_conf() regen_conf()
_tools_migrations_run_after_system_restore( _tools_migrations_run_after_system_restore(
@ -1491,6 +1497,9 @@ class RestoreManager:
"YNH_APP_BACKUP_DIR": os.path.join( "YNH_APP_BACKUP_DIR": os.path.join(
self.work_dir, "apps", app_instance_name, "backup" self.work_dir, "apps", app_instance_name, "backup"
), ),
"YNH_APP_BASEDIR": os.path.join(
self.work_dir, "apps", app_instance_name, "settings"
),
} }
) )
@ -1500,37 +1509,19 @@ class RestoreManager:
# Execute the app install script # Execute the app install script
restore_failed = True restore_failed = True
try: try:
restore_retcode = hook_exec( (
restore_failed,
failure_message_with_debug_instructions,
) = hook_exec_with_script_debug_if_failure(
restore_script, restore_script,
chdir=app_backup_in_archive, chdir=app_backup_in_archive,
env=env_dict, env=env_dict,
)[0] operation_logger=operation_logger,
# "Common" app restore failure : the script failed and returned exit code != 0 error_message_if_script_failed=m18n.n("app_restore_script_failed"),
restore_failed = True if restore_retcode != 0 else False error_message_if_failed=lambda e: m18n.n(
if restore_failed: "app_restore_failed", app=app_instance_name, error=e
error = m18n.n("app_restore_script_failed") ),
logger.error(
m18n.n("app_restore_failed", app=app_instance_name, error=error)
)
failure_message_with_debug_instructions = operation_logger.error(error)
if Moulinette.interface.type != "api":
dump_app_log_extract_for_debugging(operation_logger)
# Script got manually interrupted ... N.B. : KeyboardInterrupt does not inherit from Exception
except (KeyboardInterrupt, EOFError):
error = m18n.n("operation_interrupted")
logger.error(
m18n.n("app_restore_failed", app=app_instance_name, error=error)
) )
failure_message_with_debug_instructions = operation_logger.error(error)
# Something wrong happened in Yunohost's code (most probably hook_exec)
except Exception:
import traceback
error = m18n.n("unexpected_error", error="\n" + traceback.format_exc())
logger.error(
m18n.n("app_restore_failed", app=app_instance_name, error=error)
)
failure_message_with_debug_instructions = operation_logger.error(error)
finally: finally:
# Cleaning temporary scripts directory # Cleaning temporary scripts directory
shutil.rmtree(tmp_workdir_for_app, ignore_errors=True) shutil.rmtree(tmp_workdir_for_app, ignore_errors=True)
@ -1546,6 +1537,9 @@ class RestoreManager:
# Setup environment for remove script # Setup environment for remove script
env_dict_remove = _make_environment_for_app_script(app_instance_name) env_dict_remove = _make_environment_for_app_script(app_instance_name)
env_dict_remove["YNH_APP_BASEDIR"] = os.path.join(
self.work_dir, "apps", app_instance_name, "settings"
)
remove_operation_logger = OperationLogger( remove_operation_logger = OperationLogger(
"remove_on_failed_restore", "remove_on_failed_restore",

View file

@ -86,11 +86,8 @@ def certificate_status(domain_list, full=False):
domain_list = yunohost.domain.domain_list()["domains"] domain_list = yunohost.domain.domain_list()["domains"]
# Else, validate that yunohost knows the domains given # Else, validate that yunohost knows the domains given
else: else:
yunohost_domains_list = yunohost.domain.domain_list()["domains"]
for domain in domain_list: for domain in domain_list:
# Is it in Yunohost domain list? yunohost.domain._assert_domain_exists(domain)
if domain not in yunohost_domains_list:
raise YunohostValidationError("domain_name_unknown", domain=domain)
certificates = {} certificates = {}
@ -267,9 +264,7 @@ def _certificate_install_letsencrypt(
# Else, validate that yunohost knows the domains given # Else, validate that yunohost knows the domains given
else: else:
for domain in domain_list: for domain in domain_list:
yunohost_domains_list = yunohost.domain.domain_list()["domains"] yunohost.domain._assert_domain_exists(domain)
if domain not in yunohost_domains_list:
raise YunohostValidationError("domain_name_unknown", domain=domain)
# Is it self-signed? # Is it self-signed?
status = _get_status(domain) status = _get_status(domain)
@ -368,9 +363,8 @@ def certificate_renew(
else: else:
for domain in domain_list: for domain in domain_list:
# Is it in Yunohost dmomain list? # Is it in Yunohost domain list?
if domain not in yunohost.domain.domain_list()["domains"]: yunohost.domain._assert_domain_exists(domain)
raise YunohostValidationError("domain_name_unknown", domain=domain)
status = _get_status(domain) status = _get_status(domain)

View file

@ -36,6 +36,13 @@ class MyMigration(Migration):
logger.info(m18n.n("migration_0021_start")) logger.info(m18n.n("migration_0021_start"))
#
# Add new apt .deb signing key
#
new_apt_key = "https://forge.yunohost.org/yunohost_bullseye.asc"
check_output(f"wget -O- {new_apt_key} -q | apt-key add -qq -")
# #
# Patch sources.list # Patch sources.list
# #

1002
src/yunohost/dns.py Normal file

File diff suppressed because it is too large Load diff

View file

@ -24,13 +24,12 @@
Manage domains Manage domains
""" """
import os import os
import re from typing import Dict, Any
from moulinette import m18n, Moulinette from moulinette import m18n, Moulinette
from moulinette.core import MoulinetteError from moulinette.core import MoulinetteError
from yunohost.utils.error import YunohostError, YunohostValidationError
from moulinette.utils.log import getActionLogger from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import write_to_file from moulinette.utils.filesystem import write_to_file, read_yaml, write_to_yaml
from yunohost.app import ( from yunohost.app import (
app_ssowatconf, app_ssowatconf,
@ -39,12 +38,18 @@ from yunohost.app import (
_get_conflicting_apps, _get_conflicting_apps,
) )
from yunohost.regenconf import regen_conf, _force_clear_hashes, _process_regen_conf from yunohost.regenconf import regen_conf, _force_clear_hashes, _process_regen_conf
from yunohost.utils.network import get_public_ip from yunohost.utils.config import ConfigPanel, Question
from yunohost.utils.error import YunohostError, YunohostValidationError
from yunohost.log import is_unit_operation from yunohost.log import is_unit_operation
from yunohost.hook import hook_callback
logger = getActionLogger("yunohost.domain") logger = getActionLogger("yunohost.domain")
DOMAIN_CONFIG_PATH = "/usr/share/yunohost/other/config_domain.toml"
DOMAIN_SETTINGS_DIR = "/etc/yunohost/domains"
# Lazy dev caching to avoid re-query ldap every time we need the domain list
domain_list_cache: Dict[str, Any] = {}
def domain_list(exclude_subdomains=False): def domain_list(exclude_subdomains=False):
""" """
@ -54,6 +59,10 @@ def domain_list(exclude_subdomains=False):
exclude_subdomains -- Filter out domains that are subdomains of other declared domains exclude_subdomains -- Filter out domains that are subdomains of other declared domains
""" """
global domain_list_cache
if not exclude_subdomains and domain_list_cache:
return domain_list_cache
from yunohost.utils.ldap import _get_ldap_interface from yunohost.utils.ldap import _get_ldap_interface
ldap = _get_ldap_interface() ldap = _get_ldap_interface()
@ -83,7 +92,17 @@ def domain_list(exclude_subdomains=False):
result_list = sorted(result_list, key=cmp_domain) result_list = sorted(result_list, key=cmp_domain)
return {"domains": result_list, "main": _get_maindomain()} # Don't cache answer if using exclude_subdomains
if exclude_subdomains:
return {"domains": result_list, "main": _get_maindomain()}
domain_list_cache = {"domains": result_list, "main": _get_maindomain()}
return domain_list_cache
def _assert_domain_exists(domain):
if domain not in domain_list()["domains"]:
raise YunohostValidationError("domain_name_unknown", domain=domain)
@is_unit_operation() @is_unit_operation()
@ -152,6 +171,9 @@ def domain_add(operation_logger, domain, dyndns=False):
ldap.add("virtualdomain=%s,ou=domains" % domain, attr_dict) ldap.add("virtualdomain=%s,ou=domains" % domain, attr_dict)
except Exception as e: except Exception as e:
raise YunohostError("domain_creation_failed", domain=domain, error=e) raise YunohostError("domain_creation_failed", domain=domain, error=e)
finally:
global domain_list_cache
domain_list_cache = {}
# Don't regen these conf if we're still in postinstall # Don't regen these conf if we're still in postinstall
if os.path.exists("/etc/yunohost/installed"): if os.path.exists("/etc/yunohost/installed"):
@ -203,8 +225,8 @@ def domain_remove(operation_logger, domain, remove_apps=False, force=False):
# the 'force' here is related to the exception happening in domain_add ... # the 'force' here is related to the exception happening in domain_add ...
# we don't want to check the domain exists because the ldap add may have # we don't want to check the domain exists because the ldap add may have
# failed # failed
if not force and domain not in domain_list()["domains"]: if not force:
raise YunohostValidationError("domain_name_unknown", domain=domain) _assert_domain_exists(domain)
# Check domain is not the main domain # Check domain is not the main domain
if domain == _get_maindomain(): if domain == _get_maindomain():
@ -268,11 +290,18 @@ def domain_remove(operation_logger, domain, remove_apps=False, force=False):
ldap.remove("virtualdomain=" + domain + ",ou=domains") ldap.remove("virtualdomain=" + domain + ",ou=domains")
except Exception as e: except Exception as e:
raise YunohostError("domain_deletion_failed", domain=domain, error=e) raise YunohostError("domain_deletion_failed", domain=domain, error=e)
finally:
global domain_list_cache
domain_list_cache = {}
os.system("rm -rf /etc/yunohost/certs/%s" % domain) stuff_to_delete = [
f"/etc/yunohost/certs/{domain}",
f"/etc/yunohost/dyndns/K{domain}.+*",
f"{DOMAIN_SETTINGS_DIR}/{domain}.yml",
]
# Delete dyndns keys for this domain (if any) for stuff in stuff_to_delete:
os.system("rm -rf /etc/yunohost/dyndns/K%s.+*" % domain) os.system("rm -rf {stuff}")
# Sometime we have weird issues with the regenconf where some files # Sometime we have weird issues with the regenconf where some files
# appears as manually modified even though they weren't touched ... # appears as manually modified even though they weren't touched ...
@ -303,57 +332,6 @@ def domain_remove(operation_logger, domain, remove_apps=False, force=False):
logger.success(m18n.n("domain_deleted")) logger.success(m18n.n("domain_deleted"))
def domain_dns_conf(domain, ttl=None):
"""
Generate DNS configuration for a domain
Keyword argument:
domain -- Domain name
ttl -- Time to live
"""
if domain not in domain_list()["domains"]:
raise YunohostValidationError("domain_name_unknown", domain=domain)
ttl = 3600 if ttl is None else ttl
dns_conf = _build_dns_conf(domain, ttl)
result = ""
result += "; Basic ipv4/ipv6 records"
for record in dns_conf["basic"]:
result += "\n{name} {ttl} IN {type} {value}".format(**record)
result += "\n\n"
result += "; XMPP"
for record in dns_conf["xmpp"]:
result += "\n{name} {ttl} IN {type} {value}".format(**record)
result += "\n\n"
result += "; Mail"
for record in dns_conf["mail"]:
result += "\n{name} {ttl} IN {type} {value}".format(**record)
result += "\n\n"
result += "; Extra"
for record in dns_conf["extra"]:
result += "\n{name} {ttl} IN {type} {value}".format(**record)
for name, record_list in dns_conf.items():
if name not in ("basic", "xmpp", "mail", "extra") and record_list:
result += "\n\n"
result += "; " + name
for record in record_list:
result += "\n{name} {ttl} IN {type} {value}".format(**record)
if Moulinette.interface.type == "cli":
logger.info(m18n.n("domain_dns_conf_is_just_a_recommendation"))
return result
@is_unit_operation() @is_unit_operation()
def domain_main_domain(operation_logger, new_main_domain=None): def domain_main_domain(operation_logger, new_main_domain=None):
""" """
@ -370,8 +348,7 @@ def domain_main_domain(operation_logger, new_main_domain=None):
return {"current_main_domain": _get_maindomain()} return {"current_main_domain": _get_maindomain()}
# Check domain exists # Check domain exists
if new_main_domain not in domain_list()["domains"]: _assert_domain_exists(new_main_domain)
raise YunohostValidationError("domain_name_unknown", domain=new_main_domain)
operation_logger.related_to.append(("domain", new_main_domain)) operation_logger.related_to.append(("domain", new_main_domain))
operation_logger.start() operation_logger.start()
@ -379,7 +356,8 @@ def domain_main_domain(operation_logger, new_main_domain=None):
# Apply changes to ssl certs # Apply changes to ssl certs
try: try:
write_to_file("/etc/yunohost/current_host", new_main_domain) write_to_file("/etc/yunohost/current_host", new_main_domain)
global domain_list_cache
domain_list_cache = {}
_set_hostname(new_main_domain) _set_hostname(new_main_domain)
except Exception as e: except Exception as e:
logger.warning("%s" % e, exc_info=1) logger.warning("%s" % e, exc_info=1)
@ -395,6 +373,116 @@ def domain_main_domain(operation_logger, new_main_domain=None):
logger.success(m18n.n("main_domain_changed")) logger.success(m18n.n("main_domain_changed"))
def domain_url_available(domain, path):
"""
Check availability of a web path
Keyword argument:
domain -- The domain for the web path (e.g. your.domain.tld)
path -- The path to check (e.g. /coffee)
"""
return len(_get_conflicting_apps(domain, path)) == 0
def _get_maindomain():
with open("/etc/yunohost/current_host", "r") as f:
maindomain = f.readline().rstrip()
return maindomain
def domain_config_get(domain, key="", full=False, export=False):
"""
Display a domain configuration
"""
if full and export:
raise YunohostValidationError(
"You can't use --full and --export together.", raw_msg=True
)
if full:
mode = "full"
elif export:
mode = "export"
else:
mode = "classic"
config = DomainConfigPanel(domain)
return config.get(key, mode)
@is_unit_operation()
def domain_config_set(
operation_logger, domain, key=None, value=None, args=None, args_file=None
):
"""
Apply a new domain configuration
"""
Question.operation_logger = operation_logger
config = DomainConfigPanel(domain)
return config.set(key, value, args, args_file, operation_logger=operation_logger)
class DomainConfigPanel(ConfigPanel):
def __init__(self, domain):
_assert_domain_exists(domain)
self.domain = domain
self.save_mode = "diff"
super().__init__(
config_path=DOMAIN_CONFIG_PATH,
save_path=f"{DOMAIN_SETTINGS_DIR}/{domain}.yml",
)
def _get_toml(self):
from yunohost.dns import _get_registrar_config_section
toml = super()._get_toml()
toml["feature"]["xmpp"]["xmpp"]["default"] = (
1 if self.domain == _get_maindomain() else 0
)
toml["dns"]["registrar"] = _get_registrar_config_section(self.domain)
# FIXME: Ugly hack to save the registar id/value and reinject it in _load_current_values ...
self.registar_id = toml["dns"]["registrar"]["registrar"]["value"]
del toml["dns"]["registrar"]["registrar"]["value"]
return toml
def _load_current_values(self):
# TODO add mechanism to share some settings with other domains on the same zone
super()._load_current_values()
# FIXME: Ugly hack to save the registar id/value and reinject it in _load_current_values ...
self.values["registrar"] = self.registar_id
def _get_domain_settings(domain: str) -> dict:
_assert_domain_exists(domain)
if os.path.exists(f"{DOMAIN_SETTINGS_DIR}/{domain}.yml"):
return read_yaml(f"{DOMAIN_SETTINGS_DIR}/{domain}.yml") or {}
else:
return {}
def _set_domain_settings(domain: str, settings: dict) -> None:
_assert_domain_exists(domain)
write_to_yaml(f"{DOMAIN_SETTINGS_DIR}/{domain}.yml", settings)
#
#
# Stuff managed in other files
#
#
def domain_cert_status(domain_list, full=False): def domain_cert_status(domain_list, full=False):
import yunohost.certificate import yunohost.certificate
@ -421,268 +509,17 @@ def domain_cert_renew(
) )
def domain_url_available(domain, path): def domain_dns_conf(domain):
""" return domain_dns_suggest(domain)
Check availability of a web path
Keyword argument:
domain -- The domain for the web path (e.g. your.domain.tld)
path -- The path to check (e.g. /coffee)
"""
return len(_get_conflicting_apps(domain, path)) == 0
def _get_maindomain(): def domain_dns_suggest(domain):
with open("/etc/yunohost/current_host", "r") as f: import yunohost.dns
maindomain = f.readline().rstrip()
return maindomain return yunohost.dns.domain_dns_suggest(domain)
def _build_dns_conf(domain, ttl=3600, include_empty_AAAA_if_no_ipv6=False): def domain_dns_push(domain, dry_run, force, purge):
""" import yunohost.dns
Internal function that will returns a data structure containing the needed
information to generate/adapt the dns configuration
The returned datastructure will have the following form: return yunohost.dns.domain_dns_push(domain, dry_run, force, purge)
{
"basic": [
# if ipv4 available
{"type": "A", "name": "@", "value": "123.123.123.123", "ttl": 3600},
# if ipv6 available
{"type": "AAAA", "name": "@", "value": "valid-ipv6", "ttl": 3600},
],
"xmpp": [
{"type": "SRV", "name": "_xmpp-client._tcp", "value": "0 5 5222 domain.tld.", "ttl": 3600},
{"type": "SRV", "name": "_xmpp-server._tcp", "value": "0 5 5269 domain.tld.", "ttl": 3600},
{"type": "CNAME", "name": "muc", "value": "@", "ttl": 3600},
{"type": "CNAME", "name": "pubsub", "value": "@", "ttl": 3600},
{"type": "CNAME", "name": "vjud", "value": "@", "ttl": 3600}
{"type": "CNAME", "name": "xmpp-upload", "value": "@", "ttl": 3600}
],
"mail": [
{"type": "MX", "name": "@", "value": "10 domain.tld.", "ttl": 3600},
{"type": "TXT", "name": "@", "value": "\"v=spf1 a mx ip4:123.123.123.123 ipv6:valid-ipv6 -all\"", "ttl": 3600 },
{"type": "TXT", "name": "mail._domainkey", "value": "\"v=DKIM1; k=rsa; p=some-super-long-key\"", "ttl": 3600},
{"type": "TXT", "name": "_dmarc", "value": "\"v=DMARC1; p=none\"", "ttl": 3600}
],
"extra": [
# if ipv4 available
{"type": "A", "name": "*", "value": "123.123.123.123", "ttl": 3600},
# if ipv6 available
{"type": "AAAA", "name": "*", "value": "valid-ipv6", "ttl": 3600},
{"type": "CAA", "name": "@", "value": "128 issue \"letsencrypt.org\"", "ttl": 3600},
],
"example_of_a_custom_rule": [
{"type": "SRV", "name": "_matrix", "value": "domain.tld.", "ttl": 3600}
],
}
"""
ipv4 = get_public_ip()
ipv6 = get_public_ip(6)
###########################
# Basic ipv4/ipv6 records #
###########################
basic = []
if ipv4:
basic.append(["@", ttl, "A", ipv4])
if ipv6:
basic.append(["@", ttl, "AAAA", ipv6])
elif include_empty_AAAA_if_no_ipv6:
basic.append(["@", ttl, "AAAA", None])
#########
# Email #
#########
mail = [
["@", ttl, "MX", "10 %s." % domain],
["@", ttl, "TXT", '"v=spf1 a mx -all"'],
]
# DKIM/DMARC record
dkim_host, dkim_publickey = _get_DKIM(domain)
if dkim_host:
mail += [
[dkim_host, ttl, "TXT", dkim_publickey],
["_dmarc", ttl, "TXT", '"v=DMARC1; p=none"'],
]
########
# XMPP #
########
xmpp = [
["_xmpp-client._tcp", ttl, "SRV", "0 5 5222 %s." % domain],
["_xmpp-server._tcp", ttl, "SRV", "0 5 5269 %s." % domain],
["muc", ttl, "CNAME", "@"],
["pubsub", ttl, "CNAME", "@"],
["vjud", ttl, "CNAME", "@"],
["xmpp-upload", ttl, "CNAME", "@"],
]
#########
# Extra #
#########
extra = []
if ipv4:
extra.append(["*", ttl, "A", ipv4])
if ipv6:
extra.append(["*", ttl, "AAAA", ipv6])
elif include_empty_AAAA_if_no_ipv6:
extra.append(["*", ttl, "AAAA", None])
extra.append(["@", ttl, "CAA", '128 issue "letsencrypt.org"'])
####################
# Standard records #
####################
records = {
"basic": [
{"name": name, "ttl": ttl_, "type": type_, "value": value}
for name, ttl_, type_, value in basic
],
"xmpp": [
{"name": name, "ttl": ttl_, "type": type_, "value": value}
for name, ttl_, type_, value in xmpp
],
"mail": [
{"name": name, "ttl": ttl_, "type": type_, "value": value}
for name, ttl_, type_, value in mail
],
"extra": [
{"name": name, "ttl": ttl_, "type": type_, "value": value}
for name, ttl_, type_, value in extra
],
}
##################
# Custom records #
##################
# Defined by custom hooks ships in apps for example ...
hook_results = hook_callback("custom_dns_rules", args=[domain])
for hook_name, results in hook_results.items():
#
# There can be multiple results per hook name, so results look like
# {'/some/path/to/hook1':
# { 'state': 'succeed',
# 'stdreturn': [{'type': 'SRV',
# 'name': 'stuff.foo.bar.',
# 'value': 'yoloswag',
# 'ttl': 3600}]
# },
# '/some/path/to/hook2':
# { ... },
# [...]
#
# Loop over the sub-results
custom_records = [
v["stdreturn"] for v in results.values() if v and v["stdreturn"]
]
records[hook_name] = []
for record_list in custom_records:
# Check that record_list is indeed a list of dict
# with the required keys
if (
not isinstance(record_list, list)
or any(not isinstance(record, dict) for record in record_list)
or any(
key not in record
for record in record_list
for key in ["name", "ttl", "type", "value"]
)
):
# Display an error, mainly for app packagers trying to implement a hook
logger.warning(
"Ignored custom record from hook '%s' because the data is not a *list* of dict with keys name, ttl, type and value. Raw data : %s"
% (hook_name, record_list)
)
continue
records[hook_name].extend(record_list)
return records
def _get_DKIM(domain):
DKIM_file = "/etc/dkim/{domain}.mail.txt".format(domain=domain)
if not os.path.isfile(DKIM_file):
return (None, None)
with open(DKIM_file) as f:
dkim_content = f.read()
# Gotta manage two formats :
#
# Legacy
# -----
#
# mail._domainkey IN TXT ( "v=DKIM1; k=rsa; "
# "p=<theDKIMpublicKey>" )
#
# New
# ------
#
# mail._domainkey IN TXT ( "v=DKIM1; h=sha256; k=rsa; "
# "p=<theDKIMpublicKey>" )
is_legacy_format = " h=sha256; " not in dkim_content
# Legacy DKIM format
if is_legacy_format:
dkim = re.match(
(
r"^(?P<host>[a-z_\-\.]+)[\s]+([0-9]+[\s]+)?IN[\s]+TXT[\s]+"
r'[^"]*"v=(?P<v>[^";]+);'
r'[\s"]*k=(?P<k>[^";]+);'
r'[\s"]*p=(?P<p>[^";]+)'
),
dkim_content,
re.M | re.S,
)
else:
dkim = re.match(
(
r"^(?P<host>[a-z_\-\.]+)[\s]+([0-9]+[\s]+)?IN[\s]+TXT[\s]+"
r'[^"]*"v=(?P<v>[^";]+);'
r'[\s"]*h=(?P<h>[^";]+);'
r'[\s"]*k=(?P<k>[^";]+);'
r'[\s"]*p=(?P<p>[^";]+)'
),
dkim_content,
re.M | re.S,
)
if not dkim:
return (None, None)
if is_legacy_format:
return (
dkim.group("host"),
'"v={v}; k={k}; p={p}"'.format(
v=dkim.group("v"), k=dkim.group("k"), p=dkim.group("p")
),
)
else:
return (
dkim.group("host"),
'"v={v}; h={h}; k={k}; p={p}"'.format(
v=dkim.group("v"),
h=dkim.group("h"),
k=dkim.group("k"),
p=dkim.group("p"),
),
)

View file

@ -37,8 +37,9 @@ from moulinette.utils.filesystem import write_to_file, read_file
from moulinette.utils.network import download_json from moulinette.utils.network import download_json
from yunohost.utils.error import YunohostError, YunohostValidationError from yunohost.utils.error import YunohostError, YunohostValidationError
from yunohost.domain import _get_maindomain, _build_dns_conf from yunohost.domain import _get_maindomain
from yunohost.utils.network import get_public_ip, dig from yunohost.utils.network import get_public_ip
from yunohost.utils.dns import dig
from yunohost.log import is_unit_operation from yunohost.log import is_unit_operation
from yunohost.regenconf import regen_conf from yunohost.regenconf import regen_conf
@ -224,9 +225,8 @@ def dyndns_update(
ipv6 -- IPv6 address to send ipv6 -- IPv6 address to send
""" """
# Get old ipv4/v6
old_ipv4, old_ipv6 = (None, None) # (default values) from yunohost.dns import _build_dns_conf
# If domain is not given, try to guess it from keys available... # If domain is not given, try to guess it from keys available...
if domain is None: if domain is None:
@ -307,6 +307,12 @@ def dyndns_update(
logger.debug("Old IPv4/v6 are (%s, %s)" % (old_ipv4, old_ipv6)) logger.debug("Old IPv4/v6 are (%s, %s)" % (old_ipv4, old_ipv6))
logger.debug("Requested IPv4/v6 are (%s, %s)" % (ipv4, ipv6)) logger.debug("Requested IPv4/v6 are (%s, %s)" % (ipv4, ipv6))
if ipv4 is None and ipv6 is None:
logger.debug(
"No ipv4 nor ipv6 ?! Sounds like the server is not connected to the internet, or the ip.yunohost.org infrastructure is down somehow"
)
return
# no need to update # no need to update
if (not force and not dry_run) and (old_ipv4 == ipv4 and old_ipv6 == ipv6): if (not force and not dry_run) and (old_ipv4 == ipv4 and old_ipv6 == ipv6):
logger.info("No updated needed.") logger.info("No updated needed.")

View file

@ -34,7 +34,7 @@ from importlib import import_module
from moulinette import m18n, Moulinette from moulinette import m18n, Moulinette
from yunohost.utils.error import YunohostError, YunohostValidationError from yunohost.utils.error import YunohostError, YunohostValidationError
from moulinette.utils import log from moulinette.utils import log
from moulinette.utils.filesystem import read_json from moulinette.utils.filesystem import read_yaml
HOOK_FOLDER = "/usr/share/yunohost/hooks/" HOOK_FOLDER = "/usr/share/yunohost/hooks/"
CUSTOM_HOOK_FOLDER = "/etc/yunohost/hooks.d/" CUSTOM_HOOK_FOLDER = "/etc/yunohost/hooks.d/"
@ -326,7 +326,7 @@ def hook_exec(
chdir=None, chdir=None,
env=None, env=None,
user="root", user="root",
return_format="json", return_format="yaml",
): ):
""" """
Execute hook from a file with arguments Execute hook from a file with arguments
@ -447,10 +447,10 @@ def _hook_exec_bash(path, args, chdir, env, user, return_format, loggers):
raw_content = f.read() raw_content = f.read()
returncontent = {} returncontent = {}
if return_format == "json": if return_format == "yaml":
if raw_content != "": if raw_content != "":
try: try:
returncontent = read_json(stdreturn) returncontent = read_yaml(stdreturn)
except Exception as e: except Exception as e:
raise YunohostError( raise YunohostError(
"hook_json_return_error", "hook_json_return_error",
@ -498,6 +498,40 @@ def _hook_exec_python(path, args, env, loggers):
return ret return ret
def hook_exec_with_script_debug_if_failure(*args, **kwargs):
operation_logger = kwargs.pop("operation_logger")
error_message_if_failed = kwargs.pop("error_message_if_failed")
error_message_if_script_failed = kwargs.pop("error_message_if_script_failed")
failed = True
failure_message_with_debug_instructions = None
try:
retcode, retpayload = hook_exec(*args, **kwargs)
failed = True if retcode != 0 else False
if failed:
error = error_message_if_script_failed
logger.error(error_message_if_failed(error))
failure_message_with_debug_instructions = operation_logger.error(error)
if Moulinette.interface.type != "api":
operation_logger.dump_script_log_extract_for_debugging()
# Script got manually interrupted ...
# N.B. : KeyboardInterrupt does not inherit from Exception
except (KeyboardInterrupt, EOFError):
error = m18n.n("operation_interrupted")
logger.error(error_message_if_failed(error))
failure_message_with_debug_instructions = operation_logger.error(error)
# Something wrong happened in Yunohost's code (most probably hook_exec)
except Exception:
import traceback
error = m18n.n("unexpected_error", error="\n" + traceback.format_exc())
logger.error(error_message_if_failed(error))
failure_message_with_debug_instructions = operation_logger.error(error)
return failed, failure_message_with_debug_instructions
def _extract_filename_parts(filename): def _extract_filename_parts(filename):
"""Extract hook parts from filename""" """Extract hook parts from filename"""
if "-" in filename: if "-" in filename:

View file

@ -29,6 +29,7 @@ import re
import yaml import yaml
import glob import glob
import psutil import psutil
from typing import List
from datetime import datetime, timedelta from datetime import datetime, timedelta
from logging import FileHandler, getLogger, Formatter from logging import FileHandler, getLogger, Formatter
@ -69,7 +70,13 @@ def log_list(limit=None, with_details=False, with_suboperations=False):
logs = list(reversed(sorted(logs))) logs = list(reversed(sorted(logs)))
if limit is not None: if limit is not None:
logs = logs[:limit] if with_suboperations:
logs = logs[:limit]
else:
# If we displaying only parent, we are still gonna load up to limit * 5 logs
# because many of them are suboperations which are not gonna be kept
# Yet we still want to obtain ~limit number of logs
logs = logs[: limit * 5]
for log in logs: for log in logs:
@ -122,6 +129,9 @@ def log_list(limit=None, with_details=False, with_suboperations=False):
else: else:
operations = [o for o in operations.values()] operations = [o for o in operations.values()]
if limit:
operations = operations[:limit]
operations = list(reversed(sorted(operations, key=lambda o: o["name"]))) operations = list(reversed(sorted(operations, key=lambda o: o["name"])))
# Reverse the order of log when in cli, more comfortable to read (avoid # Reverse the order of log when in cli, more comfortable to read (avoid
# unecessary scrolling) # unecessary scrolling)
@ -151,26 +161,42 @@ def log_show(
filter_irrelevant = True filter_irrelevant = True
if filter_irrelevant: if filter_irrelevant:
filters = [
r"set [+-]x$", def _filter(lines):
r"set [+-]o xtrace$", filters = [
r"local \w+$", r"set [+-]x$",
r"local legacy_args=.*$", r"set [+-]o xtrace$",
r".*Helper used in legacy mode.*", r"set [+-]o errexit$",
r"args_array=.*$", r"set [+-]o nounset$",
r"local -A args_array$", r"trap '' EXIT",
r"ynh_handle_getopts_args", r"local \w+$",
r"ynh_script_progression", r"local exit_code=(1|0)$",
] r"local legacy_args=.*$",
r"local -A args_array$",
r"args_array=.*$",
r"ret_code=1",
r".*Helper used in legacy mode.*",
r"ynh_handle_getopts_args",
r"ynh_script_progression",
r"sleep 0.5",
r"'\[' (1|0) -eq (1|0) '\]'$",
r"\[?\['? -n '' '?\]\]?$",
r"rm -rf /var/cache/yunohost/download/$",
r"type -t ynh_clean_setup$",
r"DEBUG - \+ echo '",
r"DEBUG - \+ exit (1|0)$",
]
filters = [re.compile(f) for f in filters]
return [
line
for line in lines
if not any(f.search(line.strip()) for f in filters)
]
else: else:
filters = []
def _filter_lines(lines, filters=[]): def _filter(lines):
return lines
filters = [re.compile(f) for f in filters]
return [
line for line in lines if not any(f.search(line.strip()) for f in filters)
]
# Normalize log/metadata paths and filenames # Normalize log/metadata paths and filenames
abs_path = path abs_path = path
@ -209,7 +235,7 @@ def log_show(
content += "\n============\n\n" content += "\n============\n\n"
if os.path.exists(log_path): if os.path.exists(log_path):
actual_log = read_file(log_path) actual_log = read_file(log_path)
content += "\n".join(_filter_lines(actual_log.split("\n"), filters)) content += "\n".join(_filter(actual_log.split("\n")))
url = yunopaste(content) url = yunopaste(content)
@ -282,13 +308,13 @@ def log_show(
if os.path.exists(log_path): if os.path.exists(log_path):
from yunohost.service import _tail from yunohost.service import _tail
if number and filters: if number and filter_irrelevant:
logs = _tail(log_path, int(number * 4)) logs = _tail(log_path, int(number * 4))
elif number: elif number:
logs = _tail(log_path, int(number)) logs = _tail(log_path, int(number))
else: else:
logs = read_file(log_path) logs = read_file(log_path)
logs = _filter_lines(logs, filters) logs = list(_filter(logs))
if number: if number:
logs = logs[-number:] logs = logs[-number:]
infos["log_path"] = log_path infos["log_path"] = log_path
@ -427,7 +453,7 @@ class RedactingFormatter(Formatter):
# (the secret part being at least 3 chars to avoid catching some lines like just "db_pwd=") # (the secret part being at least 3 chars to avoid catching some lines like just "db_pwd=")
# Some names like "key" or "manifest_key" are ignored, used in helpers like ynh_app_setting_set or ynh_read_manifest # Some names like "key" or "manifest_key" are ignored, used in helpers like ynh_app_setting_set or ynh_read_manifest
match = re.search( match = re.search(
r"(pwd|pass|password|passphrase|secret\w*|\w+key|token|PASSPHRASE)=(\S{3,})$", r"(pwd|pass|passwd|password|passphrase|secret\w*|\w+key|token|PASSPHRASE)=(\S{3,})$",
record.strip(), record.strip(),
) )
if ( if (
@ -453,7 +479,7 @@ class OperationLogger(object):
This class record logs and metadata like context or start time/end time. This class record logs and metadata like context or start time/end time.
""" """
_instances = [] _instances: List[object] = []
def __init__(self, operation, related_to=None, **kwargs): def __init__(self, operation, related_to=None, **kwargs):
# TODO add a way to not save password on app installation # TODO add a way to not save password on app installation
@ -707,6 +733,52 @@ class OperationLogger(object):
else: else:
self.error(m18n.n("log_operation_unit_unclosed_properly")) self.error(m18n.n("log_operation_unit_unclosed_properly"))
def dump_script_log_extract_for_debugging(self):
with open(self.log_path, "r") as f:
lines = f.readlines()
filters = [
r"set [+-]x$",
r"set [+-]o xtrace$",
r"local \w+$",
r"local legacy_args=.*$",
r".*Helper used in legacy mode.*",
r"args_array=.*$",
r"local -A args_array$",
r"ynh_handle_getopts_args",
r"ynh_script_progression",
]
filters = [re.compile(f_) for f_ in filters]
lines_to_display = []
for line in lines:
if ": " not in line.strip():
continue
# A line typically looks like
# 2019-10-19 16:10:27,611: DEBUG - + mysql -u piwigo --password=********** -B piwigo
# And we just want the part starting by "DEBUG - "
line = line.strip().split(": ", 1)[1]
if any(filter_.search(line) for filter_ in filters):
continue
lines_to_display.append(line)
if line.endswith("+ ynh_exit_properly") or " + ynh_die " in line:
break
elif len(lines_to_display) > 20:
lines_to_display.pop(0)
logger.warning(
"Here's an extract of the logs before the crash. It might help debugging the error:"
)
for line in lines_to_display:
logger.info(line)
def _get_datetime_from_name(name): def _get_datetime_from_name(name):

View file

@ -457,22 +457,26 @@ def permission_create(
"permission_creation_failed", permission=permission, error=e "permission_creation_failed", permission=permission, error=e
) )
permission_url( try:
permission, permission_url(
url=url, permission,
add_url=additional_urls, url=url,
auth_header=auth_header, add_url=additional_urls,
sync_perm=False, auth_header=auth_header,
) sync_perm=False,
)
new_permission = _update_ldap_group_permission( new_permission = _update_ldap_group_permission(
permission=permission, permission=permission,
allowed=allowed, allowed=allowed,
label=label, label=label,
show_tile=show_tile, show_tile=show_tile,
protected=protected, protected=protected,
sync_perm=sync_perm, sync_perm=sync_perm,
) )
except:
permission_delete(permission, force=True)
raise
logger.debug(m18n.n("permission_created", permission=permission)) logger.debug(m18n.n("permission_created", permission=permission))
return new_permission return new_permission
@ -860,11 +864,9 @@ def _validate_and_sanitize_permission_url(url, app_base_path, app):
re:^/api/.*|/scripts/api.js$ re:^/api/.*|/scripts/api.js$
""" """
from yunohost.domain import domain_list from yunohost.domain import _assert_domain_exists
from yunohost.app import _assert_no_conflicting_apps from yunohost.app import _assert_no_conflicting_apps
domains = domain_list()["domains"]
# #
# Regexes # Regexes
# #
@ -896,8 +898,8 @@ def _validate_and_sanitize_permission_url(url, app_base_path, app):
domain, path = url[3:].split("/", 1) domain, path = url[3:].split("/", 1)
path = "/" + path path = "/" + path
if domain.replace("%", "").replace("\\", "") not in domains: domain_with_no_regex = domain.replace("%", "").replace("\\", "")
raise YunohostValidationError("domain_name_unknown", domain=domain) _assert_domain_exists(domain_with_no_regex)
validate_regex(path) validate_regex(path)
@ -931,8 +933,7 @@ def _validate_and_sanitize_permission_url(url, app_base_path, app):
domain, path = split_domain_path(url) domain, path = split_domain_path(url)
sanitized_url = domain + path sanitized_url = domain + path
if domain not in domains: _assert_domain_exists(domain)
raise YunohostValidationError("domain_name_unknown", domain=domain)
_assert_no_conflicting_apps(domain, path, ignore_app=app) _assert_no_conflicting_apps(domain, path, ignore_app=app)

View file

@ -105,13 +105,9 @@ def regen_conf(
else: else:
filesystem.mkdir(PENDING_CONF_DIR, 0o755, True) filesystem.mkdir(PENDING_CONF_DIR, 0o755, True)
# Format common hooks arguments
common_args = [1 if force else 0, 1 if dry_run else 0]
# Execute hooks for pre-regen # Execute hooks for pre-regen
pre_args = [ # element 2 and 3 with empty string is because of legacy...
"pre", pre_args = ["pre", "", ""]
] + common_args
def _pre_call(name, priority, path, args): def _pre_call(name, priority, path, args):
# create the pending conf directory for the category # create the pending conf directory for the category
@ -417,9 +413,8 @@ def regen_conf(
return result return result
# Execute hooks for post-regen # Execute hooks for post-regen
post_args = [ # element 2 and 3 with empty string is because of legacy...
"post", post_args = ["post", "", ""]
] + common_args
def _pre_call(name, priority, path, args): def _pre_call(name, priority, path, args):
# append coma-separated applied changes for the category # append coma-separated applied changes for the category

View file

@ -243,7 +243,7 @@ def service_restart(names):
) )
def service_reload_or_restart(names): def service_reload_or_restart(names, test_conf=True):
""" """
Reload one or more services if they support it. If not, restart them instead. If the services are not running yet, they will be started. Reload one or more services if they support it. If not, restart them instead. If the services are not running yet, they will be started.
@ -253,7 +253,36 @@ def service_reload_or_restart(names):
""" """
if isinstance(names, str): if isinstance(names, str):
names = [names] names = [names]
services = _get_services()
for name in names: for name in names:
logger.debug(f"Reloading service {name}")
test_conf_cmd = services.get(name, {}).get("test_conf")
if test_conf and test_conf_cmd:
p = subprocess.Popen(
test_conf_cmd,
shell=True,
executable="/bin/bash",
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
out, _ = p.communicate()
if p.returncode != 0:
errors = out.decode().strip().split("\n")
logger.error(
m18n.n(
"service_not_reloading_because_conf_broken",
name=name,
errors=errors,
)
)
continue
if _run_service_command("reload-or-restart", name): if _run_service_command("reload-or-restart", name):
logger.success(m18n.n("service_reloaded_or_restarted", service=name)) logger.success(m18n.n("service_reloaded_or_restarted", service=name))
else: else:

View file

@ -18,6 +18,9 @@ SETTINGS_PATH_OTHER_LOCATION = "/etc/yunohost/settings-%s.json"
def is_boolean(value): def is_boolean(value):
TRUE = ["true", "on", "yes", "y", "1"]
FALSE = ["false", "off", "no", "n", "0"]
""" """
Ensure a string value is intended as a boolean Ensure a string value is intended as a boolean
@ -30,9 +33,11 @@ def is_boolean(value):
""" """
if isinstance(value, bool): if isinstance(value, bool):
return True, value return True, value
if value in [0, 1]:
return True, bool(value)
elif isinstance(value, str): elif isinstance(value, str):
if str(value).lower() in ["true", "on", "yes", "false", "off", "no"]: if str(value).lower() in TRUE + FALSE:
return True, str(value).lower() in ["true", "on", "yes"] return True, str(value).lower() in TRUE
else: else:
return False, None return False, None
else: else:

View file

@ -1,14 +1,11 @@
import os import os
import pytest import pytest
import sys
import moulinette import moulinette
from moulinette import m18n, Moulinette from moulinette import m18n, Moulinette
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError
from contextlib import contextmanager from contextlib import contextmanager
sys.path.append("..")
@pytest.fixture(scope="session", autouse=True) @pytest.fixture(scope="session", autouse=True)
def clone_test_app(request): def clone_test_app(request):
@ -77,6 +74,8 @@ moulinette.core.Moulinette18n.n = new_m18nn
def pytest_cmdline_main(config): def pytest_cmdline_main(config):
import sys
sys.path.insert(0, "/usr/lib/moulinette/") sys.path.insert(0, "/usr/lib/moulinette/")
import yunohost import yunohost
@ -84,9 +83,12 @@ def pytest_cmdline_main(config):
class DummyInterface: class DummyInterface:
type = "test" type = "cli"
def prompt(*args, **kwargs): def prompt(self, *args, **kwargs):
raise NotImplementedError raise NotImplementedError
def display(self, message, *args, **kwargs):
print(message)
Moulinette._interface = DummyInterface() Moulinette._interface = DummyInterface()

View file

@ -0,0 +1,202 @@
import glob
import os
import shutil
import pytest
from .conftest import get_test_apps_dir
from moulinette.utils.filesystem import read_file
from yunohost.domain import _get_maindomain
from yunohost.app import (
app_setting,
app_install,
app_remove,
_is_installed,
app_config_get,
app_config_set,
app_ssowatconf,
)
from yunohost.utils.error import YunohostError, YunohostValidationError
def setup_function(function):
clean()
def teardown_function(function):
clean()
def clean():
# Make sure we have a ssowat
os.system("mkdir -p /etc/ssowat/")
app_ssowatconf()
test_apps = ["config_app", "legacy_app"]
for test_app in test_apps:
if _is_installed(test_app):
app_remove(test_app)
for filepath in glob.glob("/etc/nginx/conf.d/*.d/*%s*" % test_app):
os.remove(filepath)
for folderpath in glob.glob("/etc/yunohost/apps/*%s*" % test_app):
shutil.rmtree(folderpath, ignore_errors=True)
for folderpath in glob.glob("/var/www/*%s*" % test_app):
shutil.rmtree(folderpath, ignore_errors=True)
os.system("bash -c \"mysql -B 2>/dev/null <<< 'DROP DATABASE %s' \"" % test_app)
os.system(
"bash -c \"mysql -B 2>/dev/null <<< 'DROP USER %s@localhost'\"" % test_app
)
# Reset failed quota for service to avoid running into start-limit rate ?
os.system("systemctl reset-failed nginx")
os.system("systemctl start nginx")
@pytest.fixture()
def legacy_app(request):
main_domain = _get_maindomain()
app_install(
os.path.join(get_test_apps_dir(), "legacy_app_ynh"),
args="domain=%s&path=%s&is_public=%s" % (main_domain, "/", 1),
force=True,
)
def remove_app():
app_remove("legacy_app")
request.addfinalizer(remove_app)
return "legacy_app"
@pytest.fixture()
def config_app(request):
app_install(
os.path.join(get_test_apps_dir(), "config_app_ynh"),
args="",
force=True,
)
def remove_app():
app_remove("config_app")
request.addfinalizer(remove_app)
return "config_app"
def test_app_config_get(config_app):
assert isinstance(app_config_get(config_app), dict)
assert isinstance(app_config_get(config_app, full=True), dict)
assert isinstance(app_config_get(config_app, export=True), dict)
assert isinstance(app_config_get(config_app, "main"), dict)
assert isinstance(app_config_get(config_app, "main.components"), dict)
assert app_config_get(config_app, "main.components.boolean") == "0"
def test_app_config_nopanel(legacy_app):
with pytest.raises(YunohostValidationError):
app_config_get(legacy_app)
def test_app_config_get_nonexistentstuff(config_app):
with pytest.raises(YunohostValidationError):
app_config_get("nonexistent")
with pytest.raises(YunohostValidationError):
app_config_get(config_app, "nonexistent")
with pytest.raises(YunohostValidationError):
app_config_get(config_app, "main.nonexistent")
with pytest.raises(YunohostValidationError):
app_config_get(config_app, "main.components.nonexistent")
app_setting(config_app, "boolean", delete=True)
with pytest.raises(YunohostError):
app_config_get(config_app, "main.components.boolean")
def test_app_config_regular_setting(config_app):
assert app_config_get(config_app, "main.components.boolean") == "0"
app_config_set(config_app, "main.components.boolean", "no")
assert app_config_get(config_app, "main.components.boolean") == "0"
assert app_setting(config_app, "boolean") == "0"
app_config_set(config_app, "main.components.boolean", "yes")
assert app_config_get(config_app, "main.components.boolean") == "1"
assert app_setting(config_app, "boolean") == "1"
with pytest.raises(YunohostValidationError):
app_config_set(config_app, "main.components.boolean", "pwet")
def test_app_config_bind_on_file(config_app):
# c.f. conf/test.php in the config app
assert '$arg5= "Arg5 value";' in read_file("/var/www/config_app/test.php")
assert app_config_get(config_app, "bind.variable.arg5") == "Arg5 value"
assert app_setting(config_app, "arg5") is None
app_config_set(config_app, "bind.variable.arg5", "Foo Bar")
assert '$arg5= "Foo Bar";' in read_file("/var/www/config_app/test.php")
assert app_config_get(config_app, "bind.variable.arg5") == "Foo Bar"
assert app_setting(config_app, "arg5") == "Foo Bar"
def test_app_config_custom_get(config_app):
assert app_setting(config_app, "arg9") is None
assert (
"Files in /var/www"
in app_config_get(config_app, "bind.function.arg9")["ask"]["en"]
)
assert app_setting(config_app, "arg9") is None
def test_app_config_custom_validator(config_app):
# c.f. the config script
# arg8 is a password that must be at least 8 chars
assert not os.path.exists("/var/www/config_app/password")
assert app_setting(config_app, "arg8") is None
with pytest.raises(YunohostValidationError):
app_config_set(config_app, "bind.function.arg8", "pZo6i7u91h")
assert not os.path.exists("/var/www/config_app/password")
assert app_setting(config_app, "arg8") is None
def test_app_config_custom_set(config_app):
assert not os.path.exists("/var/www/config_app/password")
assert app_setting(config_app, "arg8") is None
app_config_set(config_app, "bind.function.arg8", "OneSuperStrongPassword")
assert os.path.exists("/var/www/config_app/password")
content = read_file("/var/www/config_app/password")
assert "OneSuperStrongPassword" not in content
assert content.startswith("$6$saltsalt$")
assert app_setting(config_app, "arg8") is None

View file

@ -2,6 +2,7 @@ import pytest
import os import os
import shutil import shutil
import subprocess import subprocess
from mock import patch
from .conftest import message, raiseYunohostError, get_test_apps_dir from .conftest import message, raiseYunohostError, get_test_apps_dir
@ -77,7 +78,8 @@ def setup_function(function):
if "with_permission_app_installed" in markers: if "with_permission_app_installed" in markers:
assert not app_is_installed("permissions_app") assert not app_is_installed("permissions_app")
user_create("alice", "Alice", "White", maindomain, "test123Ynh") user_create("alice", "Alice", "White", maindomain, "test123Ynh")
install_app("permissions_app_ynh", "/urlpermissionapp" "&admin=alice") with patch.object(os, "isatty", return_value=False):
install_app("permissions_app_ynh", "/urlpermissionapp" "&admin=alice")
assert app_is_installed("permissions_app") assert app_is_installed("permissions_app")
if "with_custom_domain" in markers: if "with_custom_domain" in markers:
@ -469,7 +471,7 @@ def test_restore_app_script_failure_handling(monkeypatch, mocker):
monkeypatch.undo() monkeypatch.undo()
return (1, None) return (1, None)
monkeypatch.setattr("yunohost.backup.hook_exec", custom_hook_exec) monkeypatch.setattr("yunohost.hook.hook_exec", custom_hook_exec)
assert not _is_installed("wordpress") assert not _is_installed("wordpress")

View file

@ -0,0 +1,80 @@
import pytest
from moulinette.utils.filesystem import read_toml
from yunohost.domain import domain_add, domain_remove
from yunohost.dns import (
DOMAIN_REGISTRAR_LIST_PATH,
_get_dns_zone_for_domain,
_get_registrar_config_section,
_build_dns_conf,
)
def setup_function(function):
clean()
def teardown_function(function):
clean()
def clean():
pass
# DNS utils testing
def test_get_dns_zone_from_domain_existing():
assert _get_dns_zone_for_domain("yunohost.org") == "yunohost.org"
assert _get_dns_zone_for_domain("donate.yunohost.org") == "yunohost.org"
assert _get_dns_zone_for_domain("fr.wikipedia.org") == "wikipedia.org"
assert _get_dns_zone_for_domain("www.fr.wikipedia.org") == "wikipedia.org"
assert (
_get_dns_zone_for_domain("non-existing-domain.yunohost.org") == "yunohost.org"
)
assert _get_dns_zone_for_domain("yolo.nohost.me") == "nohost.me"
assert _get_dns_zone_for_domain("foo.yolo.nohost.me") == "nohost.me"
assert _get_dns_zone_for_domain("yolo.tld") == "yolo.tld"
assert _get_dns_zone_for_domain("foo.yolo.tld") == "yolo.tld"
# Domain registrar testing
def test_registrar_list_integrity():
assert read_toml(DOMAIN_REGISTRAR_LIST_PATH)
def test_magic_guess_registrar_weird_domain():
assert _get_registrar_config_section("yolo.tld")["registrar"]["value"] is None
def test_magic_guess_registrar_ovh():
assert (
_get_registrar_config_section("yolo.yunohost.org")["registrar"]["value"]
== "ovh"
)
def test_magic_guess_registrar_yunodyndns():
assert (
_get_registrar_config_section("yolo.nohost.me")["registrar"]["value"]
== "yunohost"
)
@pytest.fixture
def example_domain():
domain_add("example.tld")
yield "example.tld"
domain_remove("example.tld")
def test_domain_dns_suggest(example_domain):
assert _build_dns_conf(example_domain)
# def domain_dns_push(domain, dry_run):
# import yunohost.dns
# return yunohost.dns.domain_registrar_push(domain, dry_run)

View file

@ -0,0 +1,118 @@
import pytest
import os
from moulinette.core import MoulinetteError
from yunohost.utils.error import YunohostValidationError
from yunohost.domain import (
DOMAIN_SETTINGS_DIR,
_get_maindomain,
domain_add,
domain_remove,
domain_list,
domain_main_domain,
domain_config_get,
domain_config_set,
)
TEST_DOMAINS = ["example.tld", "sub.example.tld", "other-example.com"]
def setup_function(function):
# Save domain list in variable to avoid multiple calls to domain_list()
domains = domain_list()["domains"]
# First domain is main domain
if not TEST_DOMAINS[0] in domains:
domain_add(TEST_DOMAINS[0])
else:
# Reset settings if any
os.system(f"rm -rf {DOMAIN_SETTINGS_DIR}/{TEST_DOMAINS[0]}.yml")
if not _get_maindomain() == TEST_DOMAINS[0]:
domain_main_domain(TEST_DOMAINS[0])
# Clear other domains
for domain in domains:
if domain not in TEST_DOMAINS or domain == TEST_DOMAINS[2]:
# Clean domains not used for testing
domain_remove(domain)
elif domain in TEST_DOMAINS:
# Reset settings if any
os.system(f"rm -rf {DOMAIN_SETTINGS_DIR}/{domain}.yml")
# Create classical second domain of not exist
if TEST_DOMAINS[1] not in domains:
domain_add(TEST_DOMAINS[1])
# Third domain is not created
clean()
def teardown_function(function):
clean()
def clean():
pass
# Domains management testing
def test_domain_add():
assert TEST_DOMAINS[2] not in domain_list()["domains"]
domain_add(TEST_DOMAINS[2])
assert TEST_DOMAINS[2] in domain_list()["domains"]
def test_domain_add_existing_domain():
with pytest.raises(MoulinetteError):
assert TEST_DOMAINS[1] in domain_list()["domains"]
domain_add(TEST_DOMAINS[1])
def test_domain_remove():
assert TEST_DOMAINS[1] in domain_list()["domains"]
domain_remove(TEST_DOMAINS[1])
assert TEST_DOMAINS[1] not in domain_list()["domains"]
def test_main_domain():
current_main_domain = _get_maindomain()
assert domain_main_domain()["current_main_domain"] == current_main_domain
def test_main_domain_change_unknown():
with pytest.raises(YunohostValidationError):
domain_main_domain(TEST_DOMAINS[2])
def test_change_main_domain():
assert _get_maindomain() != TEST_DOMAINS[1]
domain_main_domain(TEST_DOMAINS[1])
assert _get_maindomain() == TEST_DOMAINS[1]
# Domain settings testing
def test_domain_config_get_default():
assert domain_config_get(TEST_DOMAINS[0], "feature.xmpp.xmpp") == 1
assert domain_config_get(TEST_DOMAINS[1], "feature.xmpp.xmpp") == 0
def test_domain_config_get_export():
assert domain_config_get(TEST_DOMAINS[0], export=True)["xmpp"] == 1
assert domain_config_get(TEST_DOMAINS[1], export=True)["xmpp"] == 0
def test_domain_config_set():
assert domain_config_get(TEST_DOMAINS[1], "feature.xmpp.xmpp") == 0
domain_config_set(TEST_DOMAINS[1], "feature.xmpp.xmpp", "yes")
assert domain_config_get(TEST_DOMAINS[1], "feature.xmpp.xmpp") == 1
def test_domain_configs_unknown():
with pytest.raises(YunohostValidationError):
domain_config_get(TEST_DOMAINS[2], "feature.xmpp.xmpp.xmpp")

View file

@ -9,6 +9,7 @@ from yunohost.service import (
service_add, service_add,
service_remove, service_remove,
service_log, service_log,
service_reload_or_restart,
) )
@ -38,6 +39,10 @@ def clean():
_save_services(services) _save_services(services)
if os.path.exists("/etc/nginx/conf.d/broken.conf"):
os.remove("/etc/nginx/conf.d/broken.conf")
os.system("systemctl reload-or-restart nginx")
def test_service_status_all(): def test_service_status_all():
@ -118,3 +123,20 @@ def test_service_update_to_remove_properties():
assert _get_services()["dummyservice"].get("test_status") == "false" assert _get_services()["dummyservice"].get("test_status") == "false"
service_add("dummyservice", description="dummy", test_status="") service_add("dummyservice", description="dummy", test_status="")
assert not _get_services()["dummyservice"].get("test_status") assert not _get_services()["dummyservice"].get("test_status")
def test_service_conf_broken():
os.system("echo pwet > /etc/nginx/conf.d/broken.conf")
status = service_status("nginx")
assert status["status"] == "running"
assert status["configuration"] == "broken"
assert "broken.conf" in status["configuration-details"][0]
# Service reload-or-restart should check that the conf ain't valid
# before reload-or-restart, hence the service should still be running
service_reload_or_restart("nginx")
assert status["status"] == "running"
os.remove("/etc/nginx/conf.d/broken.conf")

View file

@ -29,6 +29,7 @@ import subprocess
import time import time
from importlib import import_module from importlib import import_module
from packaging import version from packaging import version
from typing import List
from moulinette import Moulinette, m18n from moulinette import Moulinette, m18n
from moulinette.utils.log import getActionLogger from moulinette.utils.log import getActionLogger
@ -1086,7 +1087,9 @@ class Migration(object):
# Those are to be implemented by daughter classes # Those are to be implemented by daughter classes
mode = "auto" mode = "auto"
dependencies = [] # List of migration ids required before running this migration dependencies: List[
str
] = [] # List of migration ids required before running this migration
@property @property
def disclaimer(self): def disclaimer(self):

View file

@ -141,7 +141,7 @@ def user_create(
from_import=False, from_import=False,
): ):
from yunohost.domain import domain_list, _get_maindomain from yunohost.domain import domain_list, _get_maindomain, _assert_domain_exists
from yunohost.hook import hook_callback from yunohost.hook import hook_callback
from yunohost.utils.password import assert_password_is_strong_enough from yunohost.utils.password import assert_password_is_strong_enough
from yunohost.utils.ldap import _get_ldap_interface from yunohost.utils.ldap import _get_ldap_interface
@ -169,8 +169,7 @@ def user_create(
domain = maindomain domain = maindomain
# Check that the domain exists # Check that the domain exists
if domain not in domain_list()["domains"]: _assert_domain_exists(domain)
raise YunohostValidationError("domain_name_unknown", domain=domain)
mail = username + "@" + domain mail = username + "@" + domain
ldap = _get_ldap_interface() ldap = _get_ldap_interface()

1081
src/yunohost/utils/config.py Normal file

File diff suppressed because it is too large Load diff

95
src/yunohost/utils/dns.py Normal file
View file

@ -0,0 +1,95 @@
# -*- coding: utf-8 -*-
""" License
Copyright (C) 2018 YUNOHOST.ORG
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program; if not, see http://www.gnu.org/licenses
"""
import dns.resolver
from typing import List
from moulinette.utils.filesystem import read_file
YNH_DYNDNS_DOMAINS = ["nohost.me", "noho.st", "ynh.fr"]
# Lazy dev caching to avoid re-reading the file multiple time when calling
# dig() often during same yunohost operation
external_resolvers_: List[str] = []
def external_resolvers():
global external_resolvers_
if not external_resolvers_:
resolv_dnsmasq_conf = read_file("/etc/resolv.dnsmasq.conf").split("\n")
external_resolvers_ = [
r.split(" ")[1] for r in resolv_dnsmasq_conf if r.startswith("nameserver")
]
# We keep only ipv4 resolvers, otherwise on IPv4-only instances, IPv6
# will be tried anyway resulting in super-slow dig requests that'll wait
# until timeout...
external_resolvers_ = [r for r in external_resolvers_ if ":" not in r]
return external_resolvers_
def dig(
qname, rdtype="A", timeout=5, resolvers="local", edns_size=1500, full_answers=False
):
"""
Do a quick DNS request and avoid the "search" trap inside /etc/resolv.conf
"""
# It's very important to do the request with a qname ended by .
# If we don't and the domain fail, dns resolver try a second request
# by concatenate the qname with the end of the "hostname"
if not qname.endswith("."):
qname += "."
if resolvers == "local":
resolvers = ["127.0.0.1"]
elif resolvers == "force_external":
resolvers = external_resolvers()
else:
assert isinstance(resolvers, list)
resolver = dns.resolver.Resolver(configure=False)
resolver.use_edns(0, 0, edns_size)
resolver.nameservers = resolvers
# resolver.timeout is used to trigger the next DNS query on resolvers list.
# In python-dns 1.16, this value is set to 2.0. However, this means that if
# the 3 first dns resolvers in list are down, we wait 6 seconds before to
# run the DNS query to a DNS resolvers up...
# In diagnosis dnsrecords, with 10 domains this means at least 12min, too long.
resolver.timeout = 1.0
# resolver.lifetime is the timeout for resolver.query()
# By default set it to 5 seconds to allow 4 resolvers to be unreachable.
resolver.lifetime = timeout
try:
answers = resolver.query(qname, rdtype)
except (
dns.resolver.NXDOMAIN,
dns.resolver.NoNameservers,
dns.resolver.NoAnswer,
dns.exception.Timeout,
) as e:
return ("nok", (e.__class__.__name__, e))
if not full_answers:
answers = [answer.to_text() for answer in answers]
return ("ok", answers)

View file

@ -59,4 +59,4 @@ class YunohostValidationError(YunohostError):
def content(self): def content(self):
return {"error": self.strerror, "error_key": self.key} return {"error": self.strerror, "error_key": self.key, **self.kwargs}

View file

@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
""" License
Copyright (C) 2018 YUNOHOST.ORG
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program; if not, see http://www.gnu.org/licenses
"""
from moulinette import m18n
def _value_for_locale(values):
"""
Return proper value for current locale
Keyword arguments:
values -- A dict of values associated to their locale
Returns:
An utf-8 encoded string
"""
if not isinstance(values, dict):
return values
for lang in [m18n.locale, m18n.default_locale]:
try:
return values[lang]
except KeyError:
continue
# Fallback to first value
return list(values.values())[0]

View file

@ -101,7 +101,8 @@ class LDAPInterface:
except ldap.SERVER_DOWN: except ldap.SERVER_DOWN:
raise YunohostError( raise YunohostError(
"Service slapd is not running but is required to perform this action ... " "Service slapd is not running but is required to perform this action ... "
"You can try to investigate what's happening with 'systemctl status slapd'" "You can try to investigate what's happening with 'systemctl status slapd'",
raw_msg=True,
) )
# Check that we are indeed logged in with the right identity # Check that we are indeed logged in with the right identity
@ -289,7 +290,7 @@ class LDAPInterface:
attr_found[0], attr_found[0],
attr_found[1], attr_found[1],
) )
raise MoulinetteError( raise YunohostError(
"ldap_attribute_already_exists", "ldap_attribute_already_exists",
attribute=attr_found[0], attribute=attr_found[0],
value=attr_found[1], value=attr_found[1],

View file

@ -22,7 +22,6 @@ import os
import re import re
import logging import logging
import time import time
import dns.resolver
from moulinette.utils.filesystem import read_file, write_to_file from moulinette.utils.filesystem import read_file, write_to_file
from moulinette.utils.network import download_text from moulinette.utils.network import download_text
@ -124,76 +123,6 @@ def get_gateway():
return addr.popitem()[1] if len(addr) == 1 else None return addr.popitem()[1] if len(addr) == 1 else None
# Lazy dev caching to avoid re-reading the file multiple time when calling
# dig() often during same yunohost operation
external_resolvers_ = []
def external_resolvers():
global external_resolvers_
if not external_resolvers_:
resolv_dnsmasq_conf = read_file("/etc/resolv.dnsmasq.conf").split("\n")
external_resolvers_ = [
r.split(" ")[1] for r in resolv_dnsmasq_conf if r.startswith("nameserver")
]
# We keep only ipv4 resolvers, otherwise on IPv4-only instances, IPv6
# will be tried anyway resulting in super-slow dig requests that'll wait
# until timeout...
external_resolvers_ = [r for r in external_resolvers_ if ":" not in r]
return external_resolvers_
def dig(
qname, rdtype="A", timeout=5, resolvers="local", edns_size=1500, full_answers=False
):
"""
Do a quick DNS request and avoid the "search" trap inside /etc/resolv.conf
"""
# It's very important to do the request with a qname ended by .
# If we don't and the domain fail, dns resolver try a second request
# by concatenate the qname with the end of the "hostname"
if not qname.endswith("."):
qname += "."
if resolvers == "local":
resolvers = ["127.0.0.1"]
elif resolvers == "force_external":
resolvers = external_resolvers()
else:
assert isinstance(resolvers, list)
resolver = dns.resolver.Resolver(configure=False)
resolver.use_edns(0, 0, edns_size)
resolver.nameservers = resolvers
# resolver.timeout is used to trigger the next DNS query on resolvers list.
# In python-dns 1.16, this value is set to 2.0. However, this means that if
# the 3 first dns resolvers in list are down, we wait 6 seconds before to
# run the DNS query to a DNS resolvers up...
# In diagnosis dnsrecords, with 10 domains this means at least 12min, too long.
resolver.timeout = 1.0
# resolver.lifetime is the timeout for resolver.query()
# By default set it to 5 seconds to allow 4 resolvers to be unreachable.
resolver.lifetime = timeout
try:
answers = resolver.query(qname, rdtype)
except (
dns.resolver.NXDOMAIN,
dns.resolver.NoNameservers,
dns.resolver.NoAnswer,
dns.exception.Timeout,
) as e:
return ("nok", (e.__class__.__name__, e))
if not full_answers:
answers = [answer.to_text() for answer in answers]
return ("ok", answers)
def _extract_inet(string, skip_netmask=False, skip_loopback=True): def _extract_inet(string, skip_netmask=False, skip_loopback=True):
""" """
Extract IP addresses (v4 and/or v6) from a string limited to one Extract IP addresses (v4 and/or v6) from a string limited to one

View file

@ -111,8 +111,13 @@ class PasswordValidator(object):
listed = password in SMALL_PWD_LIST or self.is_in_most_used_list(password) listed = password in SMALL_PWD_LIST or self.is_in_most_used_list(password)
strength_level = self.strength_level(password) strength_level = self.strength_level(password)
if listed: if listed:
# i18n: password_listed
return ("error", "password_listed") return ("error", "password_listed")
if strength_level < self.validation_strength: if strength_level < self.validation_strength:
# i18n: password_too_simple_1
# i18n: password_too_simple_2
# i18n: password_too_simple_3
# i18n: password_too_simple_4
return ("error", "password_too_simple_%s" % self.validation_strength) return ("error", "password_too_simple_%s" % self.validation_strength)
return ("success", "") return ("success", "")

View file

@ -3,7 +3,7 @@ import json
import glob import glob
# List all locale files (except en.json being the ref) # List all locale files (except en.json being the ref)
locale_folder = "locales/" locale_folder = "../locales/"
locale_files = glob.glob(locale_folder + "*.json") locale_files = glob.glob(locale_folder + "*.json")
locale_files = [filename.split("/")[-1] for filename in locale_files] locale_files = [filename.split("/")[-1] for filename in locale_files]
locale_files.remove("en.json") locale_files.remove("en.json")

View file

@ -3,11 +3,11 @@ import re
def reformat(lang, transformations): def reformat(lang, transformations):
locale = open(f"locales/{lang}.json").read() locale = open(f"../locales/{lang}.json").read()
for pattern, replace in transformations.items(): for pattern, replace in transformations.items():
locale = re.compile(pattern).sub(replace, locale) locale = re.compile(pattern).sub(replace, locale)
open(f"locales/{lang}.json", "w").write(locale) open(f"../locales/{lang}.json", "w").write(locale)
###################################################### ######################################################

View file

@ -0,0 +1,662 @@
#################
# _ __ _ _ #
# | '_ \| | | | #
# | |_) | |_| | #
# | .__/ \__, | #
# | | __/ | #
# |_| |___/ #
# #
#################
_read_py() {
local file="$1"
local key="$2"
python3 -c "exec(open('$file').read()); print($key)"
}
ynhtest_config_read_py() {
local dummy_dir="$(mktemp -d -p $VAR_WWW)"
file="$dummy_dir/dummy.py"
cat << EOF > $dummy_dir/dummy.py
# Some comment
FOO = None
ENABLED = False
# TITLE = "Old title"
TITLE = "Lorem Ipsum"
THEME = "colib'ris"
EMAIL = "root@example.com" # This is a comment without quotes
PORT = 1234 # This is a comment without quotes
URL = 'https://yunohost.org'
DICT = {}
DICT['ldap_base'] = "ou=users,dc=yunohost,dc=org"
DICT['ldap_conf'] = {}
DICT['ldap_conf']['user'] = "camille"
# YNH_ICI
DICT['TITLE'] = "Hello world"
EOF
test "$(_read_py "$file" "FOO")" == "None"
test "$(ynh_read_var_in_file "$file" "FOO")" == "None"
test "$(_read_py "$file" "ENABLED")" == "False"
test "$(ynh_read_var_in_file "$file" "ENABLED")" == "False"
test "$(_read_py "$file" "TITLE")" == "Lorem Ipsum"
test "$(ynh_read_var_in_file "$file" "TITLE")" == "Lorem Ipsum"
test "$(_read_py "$file" "THEME")" == "colib'ris"
test "$(ynh_read_var_in_file "$file" "THEME")" == "colib'ris"
test "$(_read_py "$file" "EMAIL")" == "root@example.com"
test "$(ynh_read_var_in_file "$file" "EMAIL")" == "root@example.com"
test "$(_read_py "$file" "PORT")" == "1234"
test "$(ynh_read_var_in_file "$file" "PORT")" == "1234"
test "$(_read_py "$file" "URL")" == "https://yunohost.org"
test "$(ynh_read_var_in_file "$file" "URL")" == "https://yunohost.org"
test "$(ynh_read_var_in_file "$file" "ldap_base")" == "ou=users,dc=yunohost,dc=org"
test "$(ynh_read_var_in_file "$file" "user")" == "camille"
test "$(ynh_read_var_in_file "$file" "TITLE" "YNH_ICI")" == "Hello world"
! _read_py "$file" "NONEXISTENT"
test "$(ynh_read_var_in_file "$file" "NONEXISTENT")" == "YNH_NULL"
! _read_py "$file" "ENABLE"
test "$(ynh_read_var_in_file "$file" "ENABLE")" == "YNH_NULL"
}
ynhtest_config_write_py() {
local dummy_dir="$(mktemp -d -p $VAR_WWW)"
file="$dummy_dir/dummy.py"
cat << EOF > $dummy_dir/dummy.py
# Some comment
FOO = None
ENABLED = False
# TITLE = "Old title"
TITLE = "Lorem Ipsum"
THEME = "colib'ris"
EMAIL = "root@example.com" # This is a comment without quotes
PORT = 1234 # This is a comment without quotes
URL = 'https://yunohost.org'
DICT = {}
DICT['ldap_base'] = "ou=users,dc=yunohost,dc=org"
# YNH_ICI
DICT['TITLE'] = "Hello world"
EOF
ynh_write_var_in_file "$file" "FOO" "bar"
test "$(_read_py "$file" "FOO")" == "bar"
test "$(ynh_read_var_in_file "$file" "FOO")" == "bar"
ynh_write_var_in_file "$file" "ENABLED" "True"
test "$(_read_py "$file" "ENABLED")" == "True"
test "$(ynh_read_var_in_file "$file" "ENABLED")" == "True"
ynh_write_var_in_file "$file" "TITLE" "Foo Bar"
test "$(_read_py "$file" "TITLE")" == "Foo Bar"
test "$(ynh_read_var_in_file "$file" "TITLE")" == "Foo Bar"
ynh_write_var_in_file "$file" "THEME" "super-awesome-theme"
test "$(_read_py "$file" "THEME")" == "super-awesome-theme"
test "$(ynh_read_var_in_file "$file" "THEME")" == "super-awesome-theme"
ynh_write_var_in_file "$file" "EMAIL" "sam@domain.tld"
test "$(_read_py "$file" "EMAIL")" == "sam@domain.tld"
test "$(ynh_read_var_in_file "$file" "EMAIL")" == "sam@domain.tld"
ynh_write_var_in_file "$file" "PORT" "5678"
test "$(_read_py "$file" "PORT")" == "5678"
test "$(ynh_read_var_in_file "$file" "PORT")" == "5678"
ynh_write_var_in_file "$file" "URL" "https://domain.tld/foobar"
test "$(_read_py "$file" "URL")" == "https://domain.tld/foobar"
test "$(ynh_read_var_in_file "$file" "URL")" == "https://domain.tld/foobar"
ynh_write_var_in_file "$file" "ldap_base" "ou=users,dc=yunohost,dc=org"
test "$(ynh_read_var_in_file "$file" "ldap_base")" == "ou=users,dc=yunohost,dc=org"
ynh_write_var_in_file "$file" "TITLE" "YOLO" "YNH_ICI"
test "$(ynh_read_var_in_file "$file" "TITLE" "YNH_ICI")" == "YOLO"
! ynh_write_var_in_file "$file" "NONEXISTENT" "foobar"
! _read_py "$file" "NONEXISTENT"
test "$(ynh_read_var_in_file "$file" "NONEXISTENT")" == "YNH_NULL"
! ynh_write_var_in_file "$file" "ENABLE" "foobar"
! _read_py "$file" "ENABLE"
test "$(ynh_read_var_in_file "$file" "ENABLE")" == "YNH_NULL"
}
###############
# _ _ #
# (_) (_) #
# _ _ __ _ #
# | | '_ \| | #
# | | | | | | #
# |_|_| |_|_| #
# #
###############
_read_ini() {
local file="$1"
local key="$2"
python3 -c "import configparser; c = configparser.ConfigParser(); c.read('$file'); print(c['main']['$key'])"
}
ynhtest_config_read_ini() {
local dummy_dir="$(mktemp -d -p $VAR_WWW)"
file="$dummy_dir/dummy.ini"
cat << EOF > $file
# Some comment
; Another comment
[main]
foo = null
enabled = False
# title = Old title
title = Lorem Ipsum
theme = colib'ris
email = root@example.com ; This is a comment without quotes
port = 1234 ; This is a comment without quotes
url = https://yunohost.org
[dict]
ldap_base = ou=users,dc=yunohost,dc=org
EOF
test "$(_read_ini "$file" "foo")" == "null"
test "$(ynh_read_var_in_file "$file" "foo")" == "null"
test "$(_read_ini "$file" "enabled")" == "False"
test "$(ynh_read_var_in_file "$file" "enabled")" == "False"
test "$(_read_ini "$file" "title")" == "Lorem Ipsum"
test "$(ynh_read_var_in_file "$file" "title")" == "Lorem Ipsum"
test "$(_read_ini "$file" "theme")" == "colib'ris"
test "$(ynh_read_var_in_file "$file" "theme")" == "colib'ris"
#test "$(_read_ini "$file" "email")" == "root@example.com"
test "$(ynh_read_var_in_file "$file" "email")" == "root@example.com"
#test "$(_read_ini "$file" "port")" == "1234"
test "$(ynh_read_var_in_file "$file" "port")" == "1234"
test "$(_read_ini "$file" "url")" == "https://yunohost.org"
test "$(ynh_read_var_in_file "$file" "url")" == "https://yunohost.org"
test "$(ynh_read_var_in_file "$file" "ldap_base")" == "ou=users,dc=yunohost,dc=org"
! _read_ini "$file" "nonexistent"
test "$(ynh_read_var_in_file "$file" "nonexistent")" == "YNH_NULL"
! _read_ini "$file" "enable"
test "$(ynh_read_var_in_file "$file" "enable")" == "YNH_NULL"
}
ynhtest_config_write_ini() {
local dummy_dir="$(mktemp -d -p $VAR_WWW)"
file="$dummy_dir/dummy.ini"
cat << EOF > $file
# Some comment
; Another comment
[main]
foo = null
enabled = False
# title = Old title
title = Lorem Ipsum
theme = colib'ris
email = root@example.com # This is a comment without quotes
port = 1234 # This is a comment without quotes
url = https://yunohost.org
[dict]
ldap_base = ou=users,dc=yunohost,dc=org
EOF
ynh_write_var_in_file "$file" "foo" "bar"
test "$(_read_ini "$file" "foo")" == "bar"
test "$(ynh_read_var_in_file "$file" "foo")" == "bar"
ynh_write_var_in_file "$file" "enabled" "True"
test "$(_read_ini "$file" "enabled")" == "True"
test "$(ynh_read_var_in_file "$file" "enabled")" == "True"
ynh_write_var_in_file "$file" "title" "Foo Bar"
test "$(_read_ini "$file" "title")" == "Foo Bar"
test "$(ynh_read_var_in_file "$file" "title")" == "Foo Bar"
ynh_write_var_in_file "$file" "theme" "super-awesome-theme"
test "$(_read_ini "$file" "theme")" == "super-awesome-theme"
test "$(ynh_read_var_in_file "$file" "theme")" == "super-awesome-theme"
ynh_write_var_in_file "$file" "email" "sam@domain.tld"
test "$(_read_ini "$file" "email")" == "sam@domain.tld # This is a comment without quotes"
test "$(ynh_read_var_in_file "$file" "email")" == "sam@domain.tld"
ynh_write_var_in_file "$file" "port" "5678"
test "$(_read_ini "$file" "port")" == "5678 # This is a comment without quotes"
test "$(ynh_read_var_in_file "$file" "port")" == "5678"
ynh_write_var_in_file "$file" "url" "https://domain.tld/foobar"
test "$(_read_ini "$file" "url")" == "https://domain.tld/foobar"
test "$(ynh_read_var_in_file "$file" "url")" == "https://domain.tld/foobar"
ynh_write_var_in_file "$file" "ldap_base" "ou=users,dc=yunohost,dc=org"
test "$(ynh_read_var_in_file "$file" "ldap_base")" == "ou=users,dc=yunohost,dc=org"
! ynh_write_var_in_file "$file" "nonexistent" "foobar"
! _read_ini "$file" "nonexistent"
test "$(ynh_read_var_in_file "$file" "nonexistent")" == "YNH_NULL"
! ynh_write_var_in_file "$file" "enable" "foobar"
! _read_ini "$file" "enable"
test "$(ynh_read_var_in_file "$file" "enable")" == "YNH_NULL"
}
#############################
# _ #
# | | #
# _ _ __ _ _ __ ___ | | #
# | | | |/ _` | '_ ` _ \| | #
# | |_| | (_| | | | | | | | #
# \__, |\__,_|_| |_| |_|_| #
# __/ | #
# |___/ #
# #
#############################
_read_yaml() {
local file="$1"
local key="$2"
python3 -c "import yaml; print(yaml.safe_load(open('$file'))['$key'])"
}
ynhtest_config_read_yaml() {
local dummy_dir="$(mktemp -d -p $VAR_WWW)"
file="$dummy_dir/dummy.yml"
cat << EOF > $file
# Some comment
foo:
enabled: false
# title: old title
title: Lorem Ipsum
theme: colib'ris
email: root@example.com # This is a comment without quotes
port: 1234 # This is a comment without quotes
url: https://yunohost.org
dict:
ldap_base: ou=users,dc=yunohost,dc=org
EOF
test "$(_read_yaml "$file" "foo")" == "None"
test "$(ynh_read_var_in_file "$file" "foo")" == ""
test "$(_read_yaml "$file" "enabled")" == "False"
test "$(ynh_read_var_in_file "$file" "enabled")" == "false"
test "$(_read_yaml "$file" "title")" == "Lorem Ipsum"
test "$(ynh_read_var_in_file "$file" "title")" == "Lorem Ipsum"
test "$(_read_yaml "$file" "theme")" == "colib'ris"
test "$(ynh_read_var_in_file "$file" "theme")" == "colib'ris"
test "$(_read_yaml "$file" "email")" == "root@example.com"
test "$(ynh_read_var_in_file "$file" "email")" == "root@example.com"
test "$(_read_yaml "$file" "port")" == "1234"
test "$(ynh_read_var_in_file "$file" "port")" == "1234"
test "$(_read_yaml "$file" "url")" == "https://yunohost.org"
test "$(ynh_read_var_in_file "$file" "url")" == "https://yunohost.org"
test "$(ynh_read_var_in_file "$file" "ldap_base")" == "ou=users,dc=yunohost,dc=org"
! _read_yaml "$file" "nonexistent"
test "$(ynh_read_var_in_file "$file" "nonexistent")" == "YNH_NULL"
! _read_yaml "$file" "enable"
test "$(ynh_read_var_in_file "$file" "enable")" == "YNH_NULL"
}
ynhtest_config_write_yaml() {
local dummy_dir="$(mktemp -d -p $VAR_WWW)"
file="$dummy_dir/dummy.yml"
cat << EOF > $file
# Some comment
foo:
enabled: false
# title: old title
title: Lorem Ipsum
theme: colib'ris
email: root@example.com # This is a comment without quotes
port: 1234 # This is a comment without quotes
url: https://yunohost.org
dict:
ldap_base: ou=users,dc=yunohost,dc=org
EOF
ynh_write_var_in_file "$file" "foo" "bar"
# cat $dummy_dir/dummy.yml # to debug
! test "$(_read_yaml "$file" "foo")" == "bar" # writing broke the yaml syntax... "foo:bar" (no space aftr :)
test "$(ynh_read_var_in_file "$file" "foo")" == "bar"
ynh_write_var_in_file "$file" "enabled" "true"
test "$(_read_yaml "$file" "enabled")" == "True"
test "$(ynh_read_var_in_file "$file" "enabled")" == "true"
ynh_write_var_in_file "$file" "title" "Foo Bar"
test "$(_read_yaml "$file" "title")" == "Foo Bar"
test "$(ynh_read_var_in_file "$file" "title")" == "Foo Bar"
ynh_write_var_in_file "$file" "theme" "super-awesome-theme"
test "$(_read_yaml "$file" "theme")" == "super-awesome-theme"
test "$(ynh_read_var_in_file "$file" "theme")" == "super-awesome-theme"
ynh_write_var_in_file "$file" "email" "sam@domain.tld"
test "$(_read_yaml "$file" "email")" == "sam@domain.tld"
test "$(ynh_read_var_in_file "$file" "email")" == "sam@domain.tld"
ynh_write_var_in_file "$file" "port" "5678"
test "$(_read_yaml "$file" "port")" == "5678"
test "$(ynh_read_var_in_file "$file" "port")" == "5678"
ynh_write_var_in_file "$file" "url" "https://domain.tld/foobar"
test "$(_read_yaml "$file" "url")" == "https://domain.tld/foobar"
test "$(ynh_read_var_in_file "$file" "url")" == "https://domain.tld/foobar"
ynh_write_var_in_file "$file" "ldap_base" "ou=foobar,dc=domain,dc=tld"
test "$(ynh_read_var_in_file "$file" "ldap_base")" == "ou=foobar,dc=domain,dc=tld"
! ynh_write_var_in_file "$file" "nonexistent" "foobar"
test "$(ynh_read_var_in_file "$file" "nonexistent")" == "YNH_NULL"
! ynh_write_var_in_file "$file" "enable" "foobar"
test "$(ynh_read_var_in_file "$file" "enable")" == "YNH_NULL"
test "$(ynh_read_var_in_file "$file" "enabled")" == "true"
}
#########################
# _ #
# (_) #
# _ ___ ___ _ __ #
# | / __|/ _ \| '_ \ #
# | \__ \ (_) | | | | #
# | |___/\___/|_| |_| #
# _/ | #
# |__/ #
# #
#########################
_read_json() {
local file="$1"
local key="$2"
python3 -c "import json; print(json.load(open('$file'))['$key'])"
}
ynhtest_config_read_json() {
local dummy_dir="$(mktemp -d -p $VAR_WWW)"
file="$dummy_dir/dummy.json"
cat << EOF > $file
{
"foo": null,
"enabled": false,
"title": "Lorem Ipsum",
"theme": "colib'ris",
"email": "root@example.com",
"port": 1234,
"url": "https://yunohost.org",
"dict": {
"ldap_base": "ou=users,dc=yunohost,dc=org"
}
}
EOF
test "$(_read_json "$file" "foo")" == "None"
test "$(ynh_read_var_in_file "$file" "foo")" == "null"
test "$(_read_json "$file" "enabled")" == "False"
test "$(ynh_read_var_in_file "$file" "enabled")" == "false"
test "$(_read_json "$file" "title")" == "Lorem Ipsum"
test "$(ynh_read_var_in_file "$file" "title")" == "Lorem Ipsum"
test "$(_read_json "$file" "theme")" == "colib'ris"
test "$(ynh_read_var_in_file "$file" "theme")" == "colib'ris"
test "$(_read_json "$file" "email")" == "root@example.com"
test "$(ynh_read_var_in_file "$file" "email")" == "root@example.com"
test "$(_read_json "$file" "port")" == "1234"
test "$(ynh_read_var_in_file "$file" "port")" == "1234"
test "$(_read_json "$file" "url")" == "https://yunohost.org"
test "$(ynh_read_var_in_file "$file" "url")" == "https://yunohost.org"
test "$(ynh_read_var_in_file "$file" "ldap_base")" == "ou=users,dc=yunohost,dc=org"
! _read_json "$file" "nonexistent"
test "$(ynh_read_var_in_file "$file" "nonexistent")" == "YNH_NULL"
! _read_json "$file" "enable"
test "$(ynh_read_var_in_file "$file" "enable")" == "YNH_NULL"
}
ynhtest_config_write_json() {
local dummy_dir="$(mktemp -d -p $VAR_WWW)"
file="$dummy_dir/dummy.json"
cat << EOF > $file
{
"foo": null,
"enabled": false,
"title": "Lorem Ipsum",
"theme": "colib'ris",
"email": "root@example.com",
"port": 1234,
"url": "https://yunohost.org",
"dict": {
"ldap_base": "ou=users,dc=yunohost,dc=org"
}
}
EOF
ynh_write_var_in_file "$file" "foo" "bar"
cat $file
test "$(_read_json "$file" "foo")" == "bar"
test "$(ynh_read_var_in_file "$file" "foo")" == "bar"
ynh_write_var_in_file "$file" "enabled" "true"
cat $file
test "$(_read_json "$file" "enabled")" == "true"
test "$(ynh_read_var_in_file "$file" "enabled")" == "true"
ynh_write_var_in_file "$file" "title" "Foo Bar"
cat $file
test "$(_read_json "$file" "title")" == "Foo Bar"
test "$(ynh_read_var_in_file "$file" "title")" == "Foo Bar"
ynh_write_var_in_file "$file" "theme" "super-awesome-theme"
cat $file
test "$(_read_json "$file" "theme")" == "super-awesome-theme"
test "$(ynh_read_var_in_file "$file" "theme")" == "super-awesome-theme"
ynh_write_var_in_file "$file" "email" "sam@domain.tld"
cat $file
test "$(_read_json "$file" "email")" == "sam@domain.tld"
test "$(ynh_read_var_in_file "$file" "email")" == "sam@domain.tld"
ynh_write_var_in_file "$file" "port" "5678"
test "$(_read_json "$file" "port")" == "5678"
test "$(ynh_read_var_in_file "$file" "port")" == "5678"
ynh_write_var_in_file "$file" "url" "https://domain.tld/foobar"
test "$(_read_json "$file" "url")" == "https://domain.tld/foobar"
test "$(ynh_read_var_in_file "$file" "url")" == "https://domain.tld/foobar"
ynh_write_var_in_file "$file" "ldap_base" "ou=foobar,dc=domain,dc=tld"
test "$(ynh_read_var_in_file "$file" "ldap_base")" == "ou=foobar,dc=domain,dc=tld"
! ynh_write_var_in_file "$file" "nonexistent" "foobar"
test "$(ynh_read_var_in_file "$file" "nonexistent")" == "YNH_NULL"
! ynh_write_var_in_file "$file" "enable" "foobar"
test "$(ynh_read_var_in_file "$file" "enable")" == "YNH_NULL"
test "$(ynh_read_var_in_file "$file" "enabled")" == "true"
}
#######################
# _ #
# | | #
# _ __ | |__ _ __ #
# | '_ \| '_ \| '_ \ #
# | |_) | | | | |_) | #
# | .__/|_| |_| .__/ #
# | | | | #
# |_| |_| #
# #
#######################
_read_php() {
local file="$1"
local key="$2"
php -r "include '$file'; echo var_export(\$$key);" | sed "s/^'//g" | sed "s/'$//g"
}
ynhtest_config_read_php() {
local dummy_dir="$(mktemp -d -p $VAR_WWW)"
file="$dummy_dir/dummy.php"
cat << EOF > $file
<?php
// Some comment
\$foo = NULL;
\$enabled = false;
// \$title = "old title";
\$title = "Lorem Ipsum";
\$theme = "colib'ris";
\$email = "root@example.com"; // This is a comment without quotes
\$port = 1234; // This is a second comment without quotes
\$url = "https://yunohost.org";
\$dict = [
'ldap_base' => "ou=users,dc=yunohost,dc=org",
'ldap_conf' => []
];
\$dict['ldap_conf']['user'] = 'camille';
const DB_HOST = 'localhost';
?>
EOF
test "$(_read_php "$file" "foo")" == "NULL"
test "$(ynh_read_var_in_file "$file" "foo")" == "NULL"
test "$(_read_php "$file" "enabled")" == "false"
test "$(ynh_read_var_in_file "$file" "enabled")" == "false"
test "$(_read_php "$file" "title")" == "Lorem Ipsum"
test "$(ynh_read_var_in_file "$file" "title")" == "Lorem Ipsum"
test "$(_read_php "$file" "theme")" == "colib\\'ris"
test "$(ynh_read_var_in_file "$file" "theme")" == "colib'ris"
test "$(_read_php "$file" "email")" == "root@example.com"
test "$(ynh_read_var_in_file "$file" "email")" == "root@example.com"
test "$(_read_php "$file" "port")" == "1234"
test "$(ynh_read_var_in_file "$file" "port")" == "1234"
test "$(_read_php "$file" "url")" == "https://yunohost.org"
test "$(ynh_read_var_in_file "$file" "url")" == "https://yunohost.org"
test "$(ynh_read_var_in_file "$file" "ldap_base")" == "ou=users,dc=yunohost,dc=org"
test "$(ynh_read_var_in_file "$file" "user")" == "camille"
test "$(ynh_read_var_in_file "$file" "DB_HOST")" == "localhost"
! _read_php "$file" "nonexistent"
test "$(ynh_read_var_in_file "$file" "nonexistent")" == "YNH_NULL"
! _read_php "$file" "enable"
test "$(ynh_read_var_in_file "$file" "enable")" == "YNH_NULL"
}
ynhtest_config_write_php() {
local dummy_dir="$(mktemp -d -p $VAR_WWW)"
file="$dummy_dir/dummy.php"
cat << EOF > $file
<?php
// Some comment
\$foo = NULL;
\$enabled = false;
// \$title = "old title";
\$title = "Lorem Ipsum";
\$theme = "colib'ris";
\$email = "root@example.com"; // This is a comment without quotes
\$port = 1234; // This is a comment without quotes
\$url = "https://yunohost.org";
\$dict = [
'ldap_base' => "ou=users,dc=yunohost,dc=org",
];
?>
EOF
ynh_write_var_in_file "$file" "foo" "bar"
test "$(_read_php "$file" "foo")" == "bar"
test "$(ynh_read_var_in_file "$file" "foo")" == "bar"
ynh_write_var_in_file "$file" "enabled" "true"
test "$(_read_php "$file" "enabled")" == "true"
test "$(ynh_read_var_in_file "$file" "enabled")" == "true"
ynh_write_var_in_file "$file" "title" "Foo Bar"
cat $file
test "$(_read_php "$file" "title")" == "Foo Bar"
test "$(ynh_read_var_in_file "$file" "title")" == "Foo Bar"
ynh_write_var_in_file "$file" "theme" "super-awesome-theme"
cat $file
test "$(_read_php "$file" "theme")" == "super-awesome-theme"
test "$(ynh_read_var_in_file "$file" "theme")" == "super-awesome-theme"
ynh_write_var_in_file "$file" "email" "sam@domain.tld"
cat $file
test "$(_read_php "$file" "email")" == "sam@domain.tld"
test "$(ynh_read_var_in_file "$file" "email")" == "sam@domain.tld"
ynh_write_var_in_file "$file" "port" "5678"
test "$(_read_php "$file" "port")" == "5678"
test "$(ynh_read_var_in_file "$file" "port")" == "5678"
ynh_write_var_in_file "$file" "url" "https://domain.tld/foobar"
test "$(_read_php "$file" "url")" == "https://domain.tld/foobar"
test "$(ynh_read_var_in_file "$file" "url")" == "https://domain.tld/foobar"
ynh_write_var_in_file "$file" "ldap_base" "ou=foobar,dc=domain,dc=tld"
test "$(ynh_read_var_in_file "$file" "ldap_base")" == "ou=foobar,dc=domain,dc=tld"
! ynh_write_var_in_file "$file" "nonexistent" "foobar"
test "$(ynh_read_var_in_file "$file" "nonexistent")" == "YNH_NULL"
! ynh_write_var_in_file "$file" "enable" "foobar"
test "$(ynh_read_var_in_file "$file" "enable")" == "YNH_NULL"
test "$(ynh_read_var_in_file "$file" "enabled")" == "true"
}

View file

@ -6,14 +6,7 @@ import glob
import json import json
import yaml import yaml
import subprocess import subprocess
import toml
ignore = [
"password_too_simple_",
"password_listed",
"backup_method_",
"backup_applying_method_",
"confirm_app_install_",
]
############################################################################### ###############################################################################
# Find used keys in python code # # Find used keys in python code #
@ -137,33 +130,23 @@ def find_expected_string_keys():
yield "backup_applying_method_%s" % method yield "backup_applying_method_%s" % method
yield "backup_method_%s_finished" % method yield "backup_method_%s_finished" % method
for level in ["danger", "thirdparty", "warning"]: registrars = toml.load(open("data/other/registrar_list.toml"))
yield "confirm_app_install_%s" % level supported_registrars = ["ovh", "gandi", "godaddy"]
for registrar in supported_registrars:
for key in registrars[registrar].keys():
yield f"domain_config_{key}"
for errortype in ["not_found", "error", "warning", "success", "not_found_details"]: domain_config = toml.load(open("data/other/config_domain.toml"))
yield "diagnosis_domain_expiration_%s" % errortype for panel in domain_config.values():
yield "diagnosis_domain_not_found_details" if not isinstance(panel, dict):
continue
for errortype in ["bad_status_code", "connection_error", "timeout"]: for section in panel.values():
yield "diagnosis_http_%s" % errortype if not isinstance(section, dict):
continue
yield "password_listed" for key, values in section.items():
for i in [1, 2, 3, 4]: if not isinstance(values, dict):
yield "password_too_simple_%s" % i continue
yield f"domain_config_{key}"
checks = [
"outgoing_port_25_ok",
"ehlo_ok",
"fcrdns_ok",
"blacklist_ok",
"queue_ok",
"ehlo_bad_answer",
"ehlo_unreachable",
"ehlo_bad_answer_details",
"ehlo_unreachable_details",
]
for check in checks:
yield "diagnosis_mail_%s" % check
############################################################################### ###############################################################################

Some files were not shown because too many files have changed in this diff Show more