Merge branch 'stretch-unstable' into simplify-requirement-checks-madness

This commit is contained in:
Alexandre Aubin 2019-11-01 15:20:48 +01:00 committed by GitHub
commit aa8aefce02
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
47 changed files with 3915 additions and 2551 deletions

4
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1,4 @@
# These are supported funding model platforms
custom: https://donate.yunohost.org
liberapay: YunoHost

View file

@ -1,48 +1,43 @@
<p align="center">
<img alt="YunoHost" src="https://raw.githubusercontent.com/YunoHost/doc/master/images/logo_roundcorner.png" width="100px" />
</p>
<h1 align="center">YunoHost</h1>
<div align="center">
[![Build status](https://travis-ci.org/YunoHost/yunohost.svg?branch=stretch-unstable)](https://travis-ci.org/YunoHost/yunohost)
[![GitHub license](https://img.shields.io/github/license/YunoHost/yunohost)](https://github.com/YunoHost/yunohost/blob/stretch-unstable/LICENSE)
[![Mastodon Follow](https://img.shields.io/mastodon/follow/28084)](https://mastodon.social/@yunohost)
# YunoHost core
</div>
This repository is the core of YunoHost code.
YunoHost is an operating system aiming to simplify as much as possible the administration of a server.
This repository corresponds to the core code of YunoHost, mainly written in Python and Bash.
- [Project features](https://yunohost.org/#/whatsyunohost)
- [Project website](https://yunohost.org)
- [Bugtracker](https://github.com/YunoHost/issues).
- [Install documentation](https://yunohost.org/install)
- [Issue tracker](https://github.com/YunoHost/issues)
# Screenshots
Webadmin ([Yunohost-Admin](https://github.com/YunoHost/yunohost-admin)) | Single sign-on user portal ([SSOwat](https://github.com/YunoHost/ssowat))
--- | ---
![](https://raw.githubusercontent.com/YunoHost/doc/master/images/webadmin.png) | ![](https://raw.githubusercontent.com/YunoHost/doc/master/images/user_panel.png)
## Contributing
- You can develop on this repository using [ynh-dev](https://github.com/YunoHost/ynh-dev) with `use-git` sub-command.
- On this repository we are [following this workflow](https://yunohost.org/#/build_system_en): `stable ← testing ← unstable ← your_branch`.
- Note: If you modify Python scripts, you will have to modifiy the actions map.
- You can learn how to get started with developing on YunoHost by reading [this piece of documentation](https://yunohost.org/dev).
- Come chat with us on the [dev chatroom](https://yunohost.org/#/chat_rooms) !
- You can help translate YunoHost on our [translation platform](https://translate.yunohost.org/engage/yunohost/?utm_source=widget)
<p align="center">
<img src="https://translate.yunohost.org/widgets/yunohost/-/multi-auto.svg" alt="Translation status" />
## Repository content
- [YunoHost core Python 2.7 scripts](./src/yunohost).
- [An actionsmap](./data/actionsmap/yunohost.yml) used by moulinette.
- [Services configuration templates](./data/templates).
- [Hooks](./data/hooks).
- [Locales](./locales) for translations of `yunohost` command.
- [Shell helpers](./helpers.d) for [application packaging](https://yunohost.org/#/packaging_apps_helpers_en).
- [Modules for the XMPP server Metronome](./lib/metronome/modules).
- [Debian files](./debian) for package creation.
## How does it work?
- Python core scripts are accessible through two interfaces thanks to the [moulinette framework](https://github.com/YunoHost/moulinette):
- [CLI](https://en.wikipedia.org/wiki/Command-line_interface) for `yunohost` command.
- [API](https://en.wikipedia.org/wiki/Application_programming_interface) for [web administration module](https://github.com/YunoHost/yunohost-admin) (other modules could be implemented).
- You can find more details about how YunoHost works on this [documentation (in French)](https://yunohost.org/#/package_list_fr).
## Dependencies
- [Python 2.7](https://www.python.org/download/releases/2.7)
- [Moulinette](https://github.com/YunoHost/moulinette)
- [Bash](https://www.gnu.org/software/bash/bash.html)
- [Debian Stretch](https://www.debian.org/releases/stretch)
</p>
## License
As [other components of YunoHost core code](https://yunohost.org/#/faq_en), this repository is licensed GNU AGPL v3.
As [other components of YunoHost](https://yunohost.org/#/faq_en), this repository is licensed under GNU AGPL v3.

View file

@ -201,24 +201,34 @@ user:
subcategories:
group:
subcategory_help: Manage group
subcategory_help: Manage user groups
actions:
### user_group_list()
list:
action_help: List group
action_help: List existing groups
api: GET /users/groups
arguments:
--fields:
help: fields to fetch
nargs: "+"
-s:
full: --short
help: List only the names of groups
action: store_true
-f:
full: --full
help: Display all informations known about each groups
action: store_true
-p:
full: --include-primary-groups
help: Also display primary groups (each user has an eponym group that only contains itself)
action: store_true
default: false
### user_group_add()
add:
### user_group_create()
create:
action_help: Create group
api: POST /users/groups
arguments:
groupname:
help: The unique group name to add
help: Name of the group to be created
extra:
pattern: &pattern_groupname
- !!str ^[a-z0-9_]+$
@ -230,7 +240,7 @@ user:
api: DELETE /users/groups/<groupname>
arguments:
groupname:
help: Username to delete
help: Name of the group to be deleted
extra:
pattern: *pattern_groupname
@ -240,19 +250,19 @@ user:
api: PUT /users/groups/<groupname>
arguments:
groupname:
help: Username to update
help: Name of the group to be updated
extra:
pattern: *pattern_groupname
-a:
full: --add-user
help: User to add in group
full: --add
help: User(s) to add in the group
nargs: "*"
metavar: USERNAME
extra:
pattern: *pattern_username
-r:
full: --remove-user
help: User to remove in group
full: --remove
help: User(s) to remove in the group
nargs: "*"
metavar: USERNAME
extra:
@ -260,112 +270,62 @@ user:
### user_group_info()
info:
action_help: Get group information
action_help: Get information about a specific group
api: GET /users/groups/<groupname>
arguments:
groupname:
help: Groupname to get information
help: Name of the group to fetch info about
extra:
pattern: *pattern_username
permission:
subcategory_help: Manage user permission
subcategory_help: Manage permissions
actions:
### user_permission_list()
list:
action_help: List access to user and group
api: GET /users/permissions/<app>
action_help: List permissions and corresponding accesses
api: GET /users/permissions
arguments:
-s:
full: --short
help: Only list permission names
action: store_true
-f:
full: --full
help: Display all info known about each permission, including the full user list of each group it is granted to.
action: store_true
### user_permission_update()
update:
action_help: Manage group or user permissions
api: PUT /users/permissions/<permission>
arguments:
permission:
help: Permission to manage (e.g. mail or nextcloud or wordpress.editors)
-a:
full: --app
help: Application to manage the permission
full: --add
help: Group or usernames to grant this permission to
nargs: "*"
metavar: APP
-p:
full: --permission
help: Name of permission (main by default)
nargs: "*"
metavar: PERMISSION
-u:
full: --username
help: Username
nargs: "*"
metavar: USER
-g:
full: --group
help: Group name
nargs: "*"
metavar: GROUP
### user_permission_add()
add:
action_help: Grant access right to users and group
api: POST /users/permissions/<app>
arguments:
app:
help: Application to manage the permission
nargs: "+"
-p:
full: --permission
help: Name of permission (main by default)
nargs: "*"
metavar: PERMISSION
-u:
full: --username
help: Username
nargs: "*"
metavar: USER
metavar: GROUP_OR_USER
extra:
pattern: *pattern_username
-g:
full: --group
help: Group name
-r:
full: --remove
help: Group or usernames revoke this permission from
nargs: "*"
metavar: GROUP
metavar: GROUP_OR_USER
extra:
pattern: *pattern_username
### user_permission_remove()
remove:
action_help: Revoke access right to users and group
api: PUT /users/permissions/<app>
arguments:
app:
help: Application to manage the permission
nargs: "+"
-p:
full: --permission
help: Name of permission (main by default)
nargs: "*"
metavar: PERMISSION
-u:
full: --username
help: Username
nargs: "*"
metavar: USER
extra:
pattern: *pattern_username
-g:
full: --group
help: Group name
nargs: "*"
metavar: GROUP
extra:
pattern: *pattern_username
## user_permission_clear()
clear:
action_help: Reset access rights for the app
## user_permission_reset()
reset:
action_help: Reset allowed groups to the default (all_users) for a given permission
api: DELETE /users/permissions/<app>
arguments:
app:
help: Application to manage the permission
nargs: "+"
-p:
full: --permission
help: Name of permission (main by default)
nargs: "*"
metavar: PERMISSION
permission:
help: Permission to manage (e.g. mail or nextcloud or wordpress.editors)
ssh:
subcategory_help: Manage ssh access
@ -832,6 +792,7 @@ app:
addaccess:
action_help: Grant access right to users (everyone by default)
api: PUT /access
deprecated: true
arguments:
apps:
nargs: "+"
@ -843,6 +804,7 @@ app:
removeaccess:
action_help: Revoke access right to users (everyone by default)
api: DELETE /access
deprecated: true
arguments:
apps:
nargs: "+"
@ -854,6 +816,7 @@ app:
clearaccess:
action_help: Reset access rights for the app
api: POST /access
deprecated: true
arguments:
apps:
nargs: "+"

View file

@ -218,6 +218,27 @@ ynh_install_app_dependencies () {
fi
local dep_app=${app//_/-} # Replace all '_' by '-'
#
# Epic ugly hack to fix the goddamn dependency nightmare of sury
# Sponsored by the "Djeezusse Fokin Kraiste Why Do Adminsys Has To Be So Fucking Complicated I Should Go Grow Potatoes Instead Of This Shit" collective
# https://github.com/YunoHost/issues/issues/1407
#
# If we require to install php dependency
if echo $dependencies | grep -q 'php';
then
# And we have packages from sury installed (7.0.33-10+weirdshiftafter instead of 7.0.33-0 on debian)
if dpkg --list | grep "php7.0" | grep -q -v "7.0.33-0+deb9"
then
# And sury ain't already installed
if ! grep -nrq "sury" /etc/apt/sources.list*
then
# Re-add sury
echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/sury.list
wget -O /etc/apt/trusted.gpg.d/sury.gpg https://packages.sury.org/php/apt.gpg
fi
fi
fi
cat > /tmp/${dep_app}-ynh-deps.control << EOF # Make a control file for equivs-build
Section: misc
Priority: optional

View file

@ -40,10 +40,13 @@ ynh_use_logrotate () {
fi
if [ $# -gt 0 ] && [ "$(echo ${1:0:1})" != "-" ]; then
if [ "$(echo ${1##*.})" == "log" ]; then # Keep only the extension to check if it's a logfile
local logfile=$1 # In this case, focus logrotate on the logfile
# If the given logfile parameter already exists as a file, or if it ends up with ".log",
# we just want to manage a single file
if [ -f "$1" ] || [ "$(echo ${1##*.})" == "log" ]; then
local logfile=$1
# Otherwise we assume we want to manage a directory and all its .log file inside
else
local logfile=$1/*.log # Else, uses the directory and all logfile into it.
local logfile=$1/*.log
fi
fi
# LEGACY CODE
@ -54,7 +57,7 @@ ynh_use_logrotate () {
fi
if [ -n "$logfile" ]
then
if [ "$(echo ${logfile##*.})" != "log" ]; then # Keep only the extension to check if it's a logfile
if [ ! -f "$1" ] && [ "$(echo ${logfile##*.})" != "log" ]; then # Keep only the extension to check if it's a logfile
local logfile="$logfile/*.log" # Else, uses the directory and all logfile into it.
fi
else

View file

@ -159,7 +159,7 @@ ynh_add_protected_uris() {
ynh_app_setting()
{
ACTION="$1" APP="$2" KEY="$3" VALUE="${4:-}" python - <<EOF
import os, yaml
import os, yaml, sys
app, action = os.environ['APP'], os.environ['ACTION'].lower()
key, value = os.environ['KEY'], os.environ.get('VALUE', None)
setting_file = "/etc/yunohost/apps/%s/settings.yml" % app
@ -176,12 +176,21 @@ else:
elif action == "set":
if key in ['redirected_urls', 'redirected_regex']:
value = yaml.load(value)
if any(key.startswith(word+"_") for word in ["unprotected", "protected", "skipped"]):
sys.stderr.write("/!\\ Packagers! This app is still using the skipped/protected/unprotected_uris/regex settings which are now obsolete and deprecated... Instead, you should use the new helpers 'ynh_permission_{create,urls,update,delete}' and the 'visitors' group to initialize the public/private access. Check out the documentation at the bottom of yunohost.org/groups_and_permissions to learn how to use the new permission mechanism.\n")
settings[key] = value
else:
raise ValueError("action should either be get, set or delete")
with open(setting_file, "w") as f:
yaml.safe_dump(settings, f, default_flow_style=False)
EOF
# Fucking legacy permission management.
# We need this because app temporarily set the app as unprotected to configure it with curl...
if [[ "$3" =~ ^(unprotected|skipped)_ ]] && [[ "${4:-}" == "/" ]]
then
ynh_permission_update --permission "main" --remove "all_users" --add "visitors"
fi
}
# Check availability of a web path
@ -230,70 +239,102 @@ ynh_webpath_register () {
# Create a new permission for the app
#
# usage: ynh_permission_create --app "app" --permission "permission" --defaultdisallow [--urls "url" ["url" ...]]
# | arg: app - the application id
# example: ynh_permission_create --permission admin --url /admin --allowed alice bob
#
# usage: ynh_permission_create --permission "permission" [--url "url"] [--allowed group1 group2]
# | arg: permission - the name for the permission (by default a permission named "main" already exist)
# | arg: defaultdisallow - define if all user will be allowed by default
# | arg: urls - the list of urls for the the permission
# | arg: url - (optional) URL for which access will be allowed/forbidden
# | arg: allowed - (optional) A list of group/user to allow for the permission
#
# If provided, 'url' is assumed to be relative to the app domain/path if they
# start with '/'. For example:
# / -> domain.tld/app
# /admin -> domain.tld/app/admin
# domain.tld/app/api -> domain.tld/app/api
#
# 'url' can be later treated as a regex if it starts with "re:".
# For example:
# re:/api/[A-Z]*$ -> domain.tld/app/api/[A-Z]*$
# re:domain.tld/app/api/[A-Z]*$ -> domain.tld/app/api/[A-Z]*$
#
ynh_permission_create() {
declare -Ar args_array=( [a]=app= [p]=permission= [d]=defaultdisallow [u]=urls= )
local app
declare -Ar args_array=( [p]=permission= [u]=url= [a]=allowed= )
local permission
local defaultdisallow
local urls
local url
local allowed
ynh_handle_getopts_args "$@"
if [[ -n ${defaultdisallow:-} ]]; then
defaultdisallow=",default_allow=False"
if [[ -n ${url:-} ]]; then
url="'$url'"
else
url="None"
fi
if [[ -n ${urls:-} ]]; then
urls=",urls=['${urls//';'/"','"}']"
if [[ -n ${allowed:-} ]]; then
allowed=",allowed=['${allowed//';'/"','"}']"
fi
yunohost tools shell -c "from yunohost.permission import permission_add; permission_add('$app', '$permission' ${defaultdisallow:-} ${urls:-}, sync_perm=False)"
yunohost tools shell -c "from yunohost.permission import permission_create; permission_create('$app.$permission', url=$url ${allowed:-} , sync_perm=False)"
}
# Remove a permission for the app (note that when the app is removed all permission is automatically removed)
#
# usage: ynh_permission_remove --app "app" --permission "permission"
# | arg: app - the application id
# example: ynh_permission_delete --permission editors
#
# usage: ynh_permission_delete --permission "permission"
# | arg: permission - the name for the permission (by default a permission named "main" is removed automatically when the app is removed)
ynh_permission_remove() {
declare -Ar args_array=( [a]=app= [p]=permission= )
local app
#
ynh_permission_delete() {
declare -Ar args_array=( [p]=permission= )
local permission
ynh_handle_getopts_args "$@"
yunohost tools shell -c "from yunohost.permission import permission_remove; permission_remove('$app', '$permission', sync_perm=False)"
yunohost tools shell -c "from yunohost.permission import permission_delete; permission_delete('$app.$permission', sync_perm=False)"
}
# Add a path managed by the SSO
# Redefine the url associated to a permission
#
# usage: ynh_permission_add_path --app "app" --permission "permission" --url "url" ["url" ...]
# | arg: app - the application id
# | arg: permission - the name for the permission
# | arg: url - the FULL url for the the permission (ex domain.tld/apps/admin)
ynh_permission_add_path() {
declare -Ar args_array=( [a]=app= [p]=permission= [u]=url= )
local app
# usage: ynh_permission_url --permission "permission" --url "url"
# | arg: permission - the name for the permission (by default a permission named "main" is removed automatically when the app is removed)
# | arg: url - (optional) URL for which access will be allowed/forbidden
#
ynh_permission_url() {
declare -Ar args_array=([p]=permission= [u]=url=)
local permission
local url
ynh_handle_getopts_args "$@"
yunohost tools shell -c "from yunohost.permission import permission_update; permission_update('$app', '$permission', add_url=['${url//';'/"','"}'], sync_perm=False)"
if [[ -n ${url:-} ]]; then
url="'$url'"
else
url="None"
fi
yunohost tools shell -c "from yunohost.permission import permission_url; permission_url('$app.$permission', url=$url)"
}
# Remove a path managed by the SSO
# Update a permission for the app
#
# usage: ynh_permission_del_path --app "app" --permission "permission" --url "url" ["url" ...]
# | arg: app - the application id
# | arg: permission - the name for the permission
# | arg: url - the FULL url for the the permission (ex domain.tld/apps/admin)
ynh_permission_del_path() {
declare -Ar args_array=( [a]=app= [p]=permission= [u]=url= )
local app
# usage: ynh_permission_update --permission "permission" --add "group" ["group" ...] --remove "group" ["group" ...]
# | arg: permission - the name for the permission (by default a permission named "main" already exist)
# | arg: add - the list of group or users to enable add to the permission
# | arg: remove - the list of group or users to remove from the permission
#
# example: ynh_permission_update --permission admin --add samdoe --remove all_users
ynh_permission_update() {
declare -Ar args_array=( [p]=permission= [a]=add= [r]=remove= )
local permission
local url
local add
local remove
ynh_handle_getopts_args "$@"
yunohost tools shell -c "from yunohost.permission import permission_update; permission_update('$app', '$permission', remove_url=['${url//';'/"','"}'], sync_perm=False)"
if [[ -n ${add:-} ]]; then
add="--add ${add//';'/" "}"
fi
if [[ -n ${remove:-} ]]; then
remove="--remove ${remove//';'/" "} "
fi
yunohost user permission update "$app.$permission" ${add:-} ${remove:-}
}

View file

@ -53,9 +53,6 @@ do_pre_regen() {
else
sudo cp services.yml /etc/yunohost/services.yml
fi
mkdir -p "$pending_dir"/etc/etckeeper/
cp etckeeper.conf "$pending_dir"/etc/etckeeper/
}
_update_services() {

View file

@ -3,6 +3,5 @@ backup_dir="$1/conf/ynh/certs"
sudo mkdir -p /etc/yunohost/certs/
sudo cp -a $backup_dir/. /etc/yunohost/certs/
sudo yunohost app ssowatconf
sudo service nginx reload
sudo service metronome reload

View file

@ -57,18 +57,24 @@ children:
objectClass:
- posixGroup
- groupOfNamesYnh
cn=visitors,ou=groups:
cn: visitors
gidNumber: "4003"
objectClass:
- posixGroup
- groupOfNamesYnh
depends_children:
cn=main.mail,ou=permission:
cn: main.mail
cn=mail.main,ou=permission:
cn: mail.main
gidNumber: "5001"
objectClass:
- posixGroup
- permissionYnh
groupPermission:
- "cn=all_users,ou=groups,dc=yunohost,dc=org"
cn=main.metronome,ou=permission:
cn: main.metronome
cn=xmpp.main,ou=permission:
cn: xmpp.main
gidNumber: "5002"
objectClass:
- posixGroup

View file

@ -3,7 +3,7 @@ auth_bind = yes
ldap_version = 3
base = ou=users,dc=yunohost,dc=org
user_attrs = uidNumber=500,gidNumber=8,mailuserquota=quota_rule=*:bytes=%$
user_filter = (&(objectClass=inetOrgPerson)(uid=%n)(permission=cn=main.mail,ou=permission,dc=yunohost,dc=org))
pass_filter = (&(objectClass=inetOrgPerson)(uid=%n)(permission=cn=main.mail,ou=permission,dc=yunohost,dc=org))
user_filter = (&(objectClass=inetOrgPerson)(uid=%n)(permission=cn=mail.main,ou=permission,dc=yunohost,dc=org))
pass_filter = (&(objectClass=inetOrgPerson)(uid=%n)(permission=cn=mail.main,ou=permission,dc=yunohost,dc=org))
default_pass_scheme = SSHA

View file

@ -63,7 +63,7 @@ bantime = 600
findtime = 600
# "maxretry" is the number of failures before a host get banned.
maxretry = 5
maxretry = 10
# "backend" specifies the backend used to get files modification.
# Available options are "pyinotify", "gamin", "polling", "systemd" and "auto".

View file

@ -29,4 +29,3 @@ protocol = tcp
filter = yunohost
logpath = /var/log/nginx/*error.log
/var/log/nginx/*access.log
maxretry = 6

View file

@ -8,7 +8,7 @@ VirtualHost "{{ domain }}"
hostname = "localhost",
user = {
basedn = "ou=users,dc=yunohost,dc=org",
filter = "(&(objectClass=posixAccount)(mail=*@{{ domain }})(permission=cn=main.metronome,ou=permission,dc=yunohost,dc=org))",
filter = "(&(objectClass=posixAccount)(mail=*@{{ domain }})(permission=cn=xmpp.main,ou=permission,dc=yunohost,dc=org))",
usernamefield = "mail",
namefield = "cn",
},

View file

@ -1,5 +1,5 @@
server_host = localhost
server_port = 389
search_base = dc=yunohost,dc=org
query_filter = (&(objectClass=mailAccount)(mail=%s)(permission=cn=main.mail,ou=permission,dc=yunohost,dc=org))
query_filter = (&(objectClass=mailAccount)(mail=%s)(permission=cn=mail.main,ou=permission,dc=yunohost,dc=org))
result_attribute = uid

View file

@ -1,5 +1,5 @@
server_host = localhost
server_port = 389
search_base = dc=yunohost,dc=org
query_filter = (&(objectClass=mailAccount)(mail=%s)(permission=cn=main.mail,ou=permission,dc=yunohost,dc=org))
query_filter = (&(objectClass=mailAccount)(mail=%s)(permission=cn=mail.main,ou=permission,dc=yunohost,dc=org))
result_attribute = maildrop

View file

@ -1,43 +0,0 @@
# The VCS to use.
#VCS="hg"
VCS="git"
#VCS="bzr"
#VCS="darcs"
# Options passed to git commit when run by etckeeper.
GIT_COMMIT_OPTIONS="--quiet"
# Options passed to hg commit when run by etckeeper.
HG_COMMIT_OPTIONS=""
# Options passed to bzr commit when run by etckeeper.
BZR_COMMIT_OPTIONS=""
# Options passed to darcs record when run by etckeeper.
DARCS_COMMIT_OPTIONS="-a"
# Uncomment to avoid etckeeper committing existing changes
# to /etc automatically once per day.
#AVOID_DAILY_AUTOCOMMITS=1
# Uncomment the following to avoid special file warning
# (the option is enabled automatically by cronjob regardless).
#AVOID_SPECIAL_FILE_WARNING=1
# Uncomment to avoid etckeeper committing existing changes to
# /etc before installation. It will cancel the installation,
# so you can commit the changes by hand.
#AVOID_COMMIT_BEFORE_INSTALL=1
# The high-level package manager that's being used.
# (apt, pacman-g2, yum, zypper etc)
HIGHLEVEL_PACKAGE_MANAGER=apt
# The low-level package manager that's being used.
# (dpkg, rpm, pacman, pacman-g2, etc)
LOWLEVEL_PACKAGE_MANAGER=dpkg
# To push each commit to a remote, put the name of the remote here.
# (eg, "origin" for git). Space-separated lists of multiple remotes
# also work (eg, "origin gitlab github" for git).
PUSH_REMOTE=""

76
debian/changelog vendored
View file

@ -1,3 +1,79 @@
yunohost (3.7.0.1) testing; urgency=low
- Hotfix to avoid having a shitload of warnings displayed during the permission migration
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 31 Oct 2019 20:35:00 +0000
yunohost (3.7.0) testing; urgency=low
# ~ Major stuff
- [enh] Add group and permission mechanism (YunoHost#585, YunoHost#763, YunoHost#789, YunoHost#790, YunoHost#795, YunoHost#797, SSOwat#147, Moulinette#189, YunoHost-admin#257)
- [mod] Rework migration system to have independent migrations (YunoHost#768, YunoHost#774, YunoHost-admin#258)
- [enh] Many improvements in the way app action failures are handled (YunoHost#769, YunoHost#811)
- [enh] Improve checks for system anomalies after app operations (YunoHost#785)
- [mod] Spookier warnings for dangerous app installs (YunoHost#814, Moulinette/808f620)
- [enh] Support app manifests in toml (YunoHost#748, Moulinette#204, Moulinette/55515cb)
- [mod] Get rid of etckeeper (YunoHost#803)
- [enh] Quite a lot of messages improvements, string cleaning, language rework... (YunoHost#793, YunoHost#799, YunoHost#823, SSOwat#143, YunoHost#766, YunoHost#767, YunoHost/fd99ef0, YunoHost/92a6315, YunoHost-admin/10ea04a, Moulinette/599bec3, Moulinette#208, Moulinette#213, Moulinette/b7d415d, Moulinette/a8966b8, Moulinette/fdf9a71, Moulinette/d895ae3, Moulinette/bdf0a1c, YunoHost#817, YunoHost#823, YunoHost/79627d7, YunoHost/9ee3d23, YunoHost-admin#265)
- [i18n] Improved translations for Catalan, Occitan, French, Esperanto, Arabic, German, Spanish, Norwegian Bokmål, Portuguese
# Smaller or pretty technical fix/enh
- [enh] Add unit/functional tests for apps + improve other tests (YunoHost#779, YunoHost#808)
- [enh] Preparations for moulinette Python3 migration (Tox, Pytest and unit tests) (Moulinette#203, Moulinette#206, Moulinette#207, Moulinette#210, Moulinette#211 Moulinette#212, Moulinette/2403ee1, Moulinette/69b0d49, Moulinette/49c749c, Moulinette/2c84ee1, Moulinette/cef72f7, YunoHost/6365a26)
- [enh] Support python hooks (YunoHost#747)
- [enh] Upgrade n version + compatibility with arm64 (YunoHost#753)
- [enh] Add OpenLDAP TLS support (YunoHost#755, YunoHost/0a2d1c7, YunoHost/2dc8095)
- [enh] Improve PostgreSQL password security (YunoHost#762)
- [enh] Integrate actions/config-panel into operation logs (YunoHost#764)
- [mod] Assume that apps without any 'path' setting defined aren't webapps (YunoHost#765)
- [fix] Set dpkg vendor to YunoHost (YunoHost#749, YunoHost#772)
- [enh] Adding variable 'token' to data to redact from logs (YunoHost#783)
- [enh] Add --force and --dry-run options to 'yunohost dyndns update' (YunoHost#786)
- [fix] Don't throw a fatal error if we can't change the hostname (YunoHost/fe3ecd7)
- [enh] Dynamically evaluate proper mariadb-server-<version> (YunoHost/f0440fb)
- [fix] Bad format for backup info.json ... (YunoHost/7d0119a)
- [fix] Inline buttons responsiveness on migration screen (YunoHost-admin#259)
- [enh] Add debug logs to SSOwat (SSOwat#145)
- [enh] Add a write_to_yaml utility similar to write_to_json (Moulinette/2e2e627)
- [enh] Warn the user about long locks (Moulinette#205)
- [mod] Tweak stuff about setuptools and moulinette deps? (Moulinette/b739f27, Moulinette/da00fc9, Moulinette/d8cbbb0)
- [fix] Misc micro bugfixes or improvements (YunoHost#743, YunoHost#792, YunoHost/6f48d1d, YunoHost/d516cf8, YunoHost#819, Moulinette/83d9e77, YunoHost/63d364e, YunoHost/68e9724, YunoHost/0849adb, YunoHost/19dbe87, YunoHost/61931f2, YunoHost/6dc720f, YunoHost/4def4df, SSOwat#140, SSOwat#141, YunoHost#829)
- [doc] Fix doc building + add doc build tests with Tox (Moulinette/f1ac5b8, Moulinette/df7d478, Moulinette/74c8f79, Moulinette/bcf92c7, Moulinette/af2c80c, Moulinette/d52a574, Moulinette/307f660, Moulinette/dced104, Moulinette/ed3823b)
- [enh] READMEs improvements (YunoHost/b3398e7, SSOwat/ee67b6f, Moulinette/1541b74, Moulinette/ad1eeef, YunoHost/25afdd4, YunoHost/73741f6)
Thanks to all contributors <3 ! (accross all repo: Yunohost, Moulinette, SSOwat, Yunohost-admin) : advocatux, Aksel K., Aleks, Allan N., amirale qt, Armin P., Bram, ButterflyOfFire, Carles S. A., chema o. r., decentral1se, Emmanuel V., Etienne M., Filip B., Geoff M., htsr, Jibec, Josué, Julien J., Kayou, liberodark, ljf, lucaskev, Lukas D., madtibo, Martin D., Mélanie C., nr 458 h, pitfd, ppr, Quentí, sidddy, troll, tufek yamero, xaloc33, yalh76
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 31 Oct 2019 18:00:00 +0000
yunohost (3.6.5.3) stable; urgency=low
- [fix] More general grep for the php/sury dependency nightmare fix (followup of #809)
-- Alexandre Aubin <alex.aubin@mailoo.org> Tue, 29 Oct 2019 03:48:00 +0000
yunohost (3.6.5.2) stable; urgency=low
- [fix] Alex was drunk and released an epic stupid bug in stable (2623d385)
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 10 Oct 2019 01:00:00 +0000
yunohost (3.6.5.1) stable; urgency=low
- [mod] Change maxretry of fail2ban from 6 to 10 (fe8fd1b)
-- Alexandre Aubin <alex.aubin@mailoo.org> Tue, 08 Oct 2019 20:00:00 +0000
yunohost (3.6.5) stable; urgency=low
- [enh] Detect and warn early about unavailable full domains... (#798)
- [mod] Change maxretry of fail2ban from 6 to 10 (#802)
- [fix] Epicly ugly workaround for the goddamn dependency nighmare about sury fucking up php7.0 dependencies (#809)
- [fix] Support logfiles not ending with .log in logrotate ... (#810)
-- Alexandre Aubin <alex.aubin@mailoo.org> Tue, 08 Oct 2019 19:00:00 +0000
yunohost (3.6.4.6) stable; urgency=low
- [fix] Hopefully fix the issue about corrupted logs metadata files (d507d447, 1cec9d78)

4
debian/control vendored
View file

@ -17,7 +17,7 @@ Depends: ${python:Depends}, ${misc:Depends}
, python-toml
, glances, apt-transport-https
, dnsutils, bind9utils, unzip, git, curl, cron, wget, jq
, ca-certificates, netcat-openbsd, iproute
, ca-certificates, netcat-openbsd, iproute2
, mariadb-server, php-mysql | php-mysqlnd
, slapd, ldap-utils, sudo-ldap, libnss-ldapd, unscd, libpam-ldapd
, postfix-ldap, postfix-policyd-spf-perl, postfix-pcre, procmail, mailutils, postsrsd
@ -31,7 +31,7 @@ Depends: ${python:Depends}, ${misc:Depends}
, equivs, lsof
Recommends: yunohost-admin
, openssh-server, ntp, inetutils-ping | iputils-ping
, bash-completion, rsyslog, etckeeper
, bash-completion, rsyslog
, php-gd, php-curl, php-gettext, php-mcrypt
, python-pip
, unattended-upgrades

View file

@ -1,31 +1,31 @@
{
"action_invalid": "Acció '{action:s}' invàlida",
"admin_password": "Contrasenya d'administració",
"admin_password_change_failed": "No s'ha pogut canviar la contrasenya",
"admin_password_change_failed": "No es pot canviar la contrasenya",
"admin_password_changed": "S'ha canviat la contrasenya d'administració",
"app_already_installed": "{app:s} 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_up_to_date": "{app:s} ja està actualitzada",
"app_argument_choice_invalid": "Aquesta opció no és vàlida per l'argument '{name:s}', ha de ser una de {choices:s}",
"app_argument_invalid": "Valor invàlid per l'argument '{name:s}':{error:s}",
"app_argument_choice_invalid": "Utilitzeu una de les opcions «{choices:s}» per l'argument «{name:s}»",
"app_argument_invalid": "Escolliu un valor vàlid per l'argument «{name:s}»: {error:s}",
"app_argument_required": "Es necessita l'argument '{name:s}'",
"app_change_no_change_url_script": "L'aplicació {app_name:s} encara no permet canviar la seva URL, es possible que s'hagi d'actualitzar.",
"app_change_url_failed_nginx_reload": "No s'ha pogut tornar a carregar nginx. Aquí teniu el resultat de \"nginx -t\":\n{nginx_errors:s}",
"app_change_url_failed_nginx_reload": "No s'ha pogut tornar a carregar NGINX. Aquí teniu el resultat de \"nginx -t\":\n{nginx_errors:s}",
"app_change_url_identical_domains": "L'antic i el nou domini/camí són idèntics ('{domain:s}{path:s}'), no hi ha res per fer.",
"app_change_url_no_script": "Aquesta aplicació '{app_name:s}' encara no permet modificar la URL. Potser s'ha d'actualitzar l'aplicació.",
"app_change_url_success": "La URL de {app:s} s'ha canviat correctament a {domain:s}{path:s}",
"app_change_url_no_script": "L'aplicació '{app_name:s}' encara no permet modificar la URL. Potser s'ha d'actualitzar.",
"app_change_url_success": "La URL de {app:s} ara és {domain:s}{path:s}",
"app_extraction_failed": "No s'han pogut extreure els fitxers d'instal·lació",
"app_id_invalid": "Id de l'aplicació incorrecte",
"app_id_invalid": "ID de l'aplicació incorrecte",
"app_incompatible": "L'aplicació {app} no és compatible amb la teva versió de YunoHost",
"app_install_files_invalid": "Fitxers d'instal·lació invàlids",
"app_location_already_used": "L'aplicació '{app}' ja està instal·lada en aquest camí ({path})",
"app_make_default_location_already_used": "No es pot fer l'aplicació '{app}' per defecte en el domini {domain} ja que ja és utilitzat per una altra aplicació '{other_app}'",
"app_location_install_failed": "No s'ha pogut instal·lar l'aplicació en aquest camí ja que entra en conflicte amb l'aplicació '{other_app}' ja instal·lada a '{other_path}'",
"app_location_unavailable": "Aquesta url no està disponible o entra en conflicte amb aplicacions ja instal·lades:\n{apps:s}",
"app_manifest_invalid": "Manifest d'aplicació incorrecte: {error}",
"app_install_files_invalid": "Aquests fitxers no es poden instal·lar",
"app_location_already_used": "L'aplicació «{app}» ja està instal·lada en ({path})",
"app_make_default_location_already_used": "No es pot fer l'aplicació '{app}' per defecte en el domini «{domain}» ja que ja és utilitzat per una altra aplicació '{other_app}'",
"app_location_install_failed": "No s'ha pogut instal·lar l'aplicació aquí ja que entra en conflicte amb l'aplicació «{other_app}» ja instal·lada a «{other_path}»",
"app_location_unavailable": "Aquesta URL no està disponible o entra en conflicte amb aplicacions ja instal·lades:\n{apps:s}",
"app_manifest_invalid": "Hi ha algun error amb el manifest de l'aplicació: {error}",
"app_no_upgrade": "No hi ha cap aplicació per actualitzar",
"app_not_correctly_installed": "{app:s} sembla estar mal instal·lada",
"app_not_installed": "L'aplicació «{app:s}» no està instal·lada. Aquí hi ha la llista d'aplicacions instal·lades: {all_apps}",
"app_not_installed": "No s'ha trobat l'aplicació «{app:s}» en la llista d'aplicacions instal·lades: {all_apps}",
"app_not_properly_removed": "{app:s} no s'ha pogut suprimir correctament",
"app_package_need_update": "El paquet de l'aplicació {app} ha de ser actualitzat per poder seguir els canvis de YunoHost",
"app_removed": "{app:s} ha estat suprimida",
@ -35,22 +35,22 @@
"app_sources_fetch_failed": "No s'han pogut carregar els fitxers font, l'URL és correcta?",
"app_unknown": "Aplicació desconeguda",
"app_unsupported_remote_type": "El tipus remot utilitzat per l'aplicació no està suportat",
"app_upgrade_app_name": "Actualitzant l'aplicació {app}…",
"app_upgrade_app_name": "Actualitzant {app}…",
"app_upgrade_failed": "No s'ha pogut actualitzar {app:s}",
"app_upgrade_some_app_failed": "No s'han pogut actualitzar algunes aplicacions",
"app_upgraded": "{app:s} ha estat actualitzada",
"app_upgraded": "S'ha actualitzat {app:s}",
"appslist_corrupted_json": "No s'han pogut carregar les llistes d'aplicacions. Sembla que {filename:s} està danyat.",
"appslist_could_not_migrate": "No s'ha pogut migrar la llista d'aplicacions {appslist:s}! No s'ha pogut analitzar la URL... L'antic cronjob s'ha guardat a {bkp_file:s}.",
"appslist_fetched": "S'ha descarregat la llista d'aplicacions {appslist:s} correctament",
"appslist_migrating": "Migrant la llista d'aplicacions {appslist:s}…",
"appslist_could_not_migrate": "No s'ha pogut migrar la llista d'aplicacions «{appslist:s}»! No s'ha pogut analitzar la URL... L'antic cronjob s'ha guardat a {bkp_file:s}.",
"appslist_fetched": "S'ha actualitzat la llista d'aplicacions «{appslist:s}»",
"appslist_migrating": "Migrant la llista d'aplicacions «{appslist:s}»…",
"appslist_name_already_tracked": "Ja hi ha una llista d'aplicacions registrada amb el nom {name:s}.",
"appslist_removed": "S'ha eliminat la llista d'aplicacions {appslist:s}",
"appslist_retrieve_bad_format": "L'arxiu obtingut per la llista d'aplicacions {appslist:s} no és vàlid",
"appslist_retrieve_error": "No s'ha pogut obtenir la llista d'aplicacions remota {appslist:s}: {error:s}",
"appslist_unknown": "La llista d'aplicacions {appslist:s} es desconeguda.",
"appslist_removed": "S'ha eliminat la llista d'aplicacions «{appslist:s}»",
"appslist_retrieve_bad_format": "No s'ha pogut llegir la llista d'aplicacions obtinguda «{appslist:s}»",
"appslist_retrieve_error": "No s'ha pogut obtenir la llista d'aplicacions remota «{appslist:s}»: {error:s}",
"appslist_unknown": "La llista d'aplicacions «{appslist:s}» es desconeguda.",
"appslist_url_already_tracked": "Ja hi ha una llista d'aplicacions registrada amb al URL {url:s}.",
"ask_current_admin_password": "Contrasenya d'administrador actual",
"ask_email": "Correu electrònic",
"ask_email": "Adreça de correu electrònic",
"ask_firstname": "Nom",
"ask_lastname": "Cognom",
"ask_list_to_remove": "Llista per a suprimir",
@ -58,56 +58,56 @@
"ask_new_admin_password": "Nova contrasenya d'administrador",
"ask_password": "Contrasenya",
"ask_path": "Camí",
"backup_abstract_method": "Encara no s'ha implementat aquest mètode de copia de seguretat",
"backup_abstract_method": "Encara està per implementar aquest mètode de còpia de seguretat",
"backup_action_required": "S'ha d'especificar què s'ha de guardar",
"backup_app_failed": "No s'ha pogut fer la còpia de seguretat de l'aplicació \"{app:s}\"",
"backup_applying_method_borg": "Enviant tots els fitxers de la còpia de seguretat al repositori borg-backup…",
"backup_applying_method_copy": "Còpia de tots els fitxers a la còpia de seguretat…",
"backup_applying_method_custom": "Crida del mètode de còpia de seguretat personalitzat \"{method:s}\"…",
"backup_applying_method_tar": "Creació de l'arxiu tar de la còpia de seguretat…",
"backup_archive_app_not_found": "L'aplicació \"{app:s}\" no es troba dins l'arxiu de la còpia de seguretat",
"backup_applying_method_tar": "Creació de l'arxiu TAR de la còpia de seguretat…",
"backup_archive_app_not_found": "No s'ha pogut trobar l'aplicació «{app:s}» dins l'arxiu de la còpia de seguretat",
"backup_archive_broken_link": "No s'ha pogut accedir a l'arxiu de la còpia de seguretat (enllaç invàlid cap a {path:s})",
"backup_archive_mount_failed": "No s'ha pogut carregar l'arxiu de la còpia de seguretat",
"backup_archive_name_exists": "Ja hi ha una còpia de seguretat amb aquest nom",
"backup_archive_name_exists": "Ja hi ha una còpia de seguretat amb aquest nom.",
"backup_archive_name_unknown": "Còpia de seguretat local \"{name:s}\" desconeguda",
"backup_archive_open_failed": "No s'ha pogut obrir l'arxiu de la còpia de seguretat",
"backup_archive_system_part_not_available": "La part \"{part:s}\" del sistema no està disponible en aquesta copia de seguretat",
"backup_archive_writing_error": "No es poden afegir arxius a l'arxiu comprimit de la còpia de seguretat",
"backup_ask_for_copying_if_needed": "Alguns fitxers no s'han pogut preparar per la còpia de seguretat utilitzant el mètode que evita malgastar espai del sistema temporalment. Per fer la còpia de seguretat, s'han d'utilitzar {size:s}MB temporalment. Hi esteu d'acord?",
"backup_archive_system_part_not_available": "La part «{part:s}» del sistema no està disponible en aquesta copia de seguretat",
"backup_archive_writing_error": "No es poden afegir els arxius «{source:s}» (anomenats en l'arxiu «{dest:s}») a l'arxiu comprimit de la còpia de seguretat «{archive:s}»",
"backup_ask_for_copying_if_needed": "Voleu fer la còpia de seguretat utilitzant {size:s} MB temporalment? (S'utilitza aquest mètode ja que alguns dels fitxers no s'han pogut preparar utilitzar un mètode més eficient.)",
"backup_borg_not_implemented": "El mètode de còpia de seguretat Borg encara no està implementat",
"backup_cant_mount_uncompress_archive": "No es pot carregar en mode de lectura només el directori de l'arxiu descomprimit",
"backup_cant_mount_uncompress_archive": "No es pot carregar l'arxiu descomprimit com a protegit contra escriptura",
"backup_cleaning_failed": "No s'ha pogut netejar el directori temporal de la còpia de seguretat",
"backup_copying_to_organize_the_archive": "Copiant {size:s}MB per organitzar l'arxiu",
"backup_couldnt_bind": "No es pot lligar {src:s} amb {dest:s}.",
"backup_created": "S'ha creat la còpia de seguretat",
"backup_creating_archive": "Creant l'arxiu de la còpia de seguretat…",
"aborting": "Avortant.",
"app_not_upgraded": "Les següents aplicacions no s'han actualitzat: {apps}",
"app_start_install": "instal·lant l'aplicació {app}…",
"app_start_remove": "Eliminant l'aplicació {app}…",
"app_start_backup": "Recuperant els fitxers pels que s'ha de fer una còpia de seguretat per {app}…",
"app_start_restore": "Recuperant l'aplicació {app}…",
"app_not_upgraded": "L'aplicació «{failed_app}» no s'ha pogut actualitzar, i com a conseqüència l'actualització de les següents aplicacions ha estat cancel·lada: {apps}",
"app_start_install": "instal·lant l'aplicació «{app}»…",
"app_start_remove": "Eliminant l'aplicació «{app}»…",
"app_start_backup": "Recuperant els fitxers pels que s'ha de fer una còpia de seguretat per «{app}»…",
"app_start_restore": "Recuperant l'aplicació «{app}»…",
"app_upgrade_several_apps": "S'actualitzaran les següents aplicacions: {apps}",
"ask_new_domain": "Nou domini",
"ask_new_path": "Nou camí",
"backup_actually_backuping": "S'està creant un arxiu de còpia de seguretat a partir dels fitxers recuperats…",
"backup_creation_failed": "Ha fallat la creació de la còpia de seguretat",
"backup_actually_backuping": "Creant un arxiu de còpia de seguretat a partir dels fitxers recuperats…",
"backup_creation_failed": "No s'ha pogut crear l'arxiu de la còpia de seguretat",
"backup_csv_addition_failed": "No s'han pogut afegir fitxers per a fer-ne la còpia de seguretat al fitxer CSV",
"backup_csv_creation_failed": "No s'ha pogut crear el fitxer CSV necessari per a futures operacions de recuperació",
"backup_custom_backup_error": "El mètode de còpia de seguretat personalitzat ha fallat a l'etapa \"backup\"",
"backup_custom_mount_error": "El mètode de còpia de seguretat personalitzat ha fallat a l'etapa \"mount\"",
"backup_csv_creation_failed": "No s'ha pogut crear el fitxer CSV necessari per a la restauració",
"backup_custom_backup_error": "El mètode de còpia de seguretat personalitzat ha fallat a l'etapa «backup»",
"backup_custom_mount_error": "El mètode de còpia de seguretat personalitzat ha fallat a l'etapa «mount»",
"backup_custom_need_mount_error": "El mètode de còpia de seguretat personalitzat ha fallat a l'etapa \"need_mount\"",
"backup_delete_error": "No s'ha pogut suprimir \"{path:s}\"",
"backup_delete_error": "No s'ha pogut suprimir «{path:s}»",
"backup_deleted": "S'ha suprimit la còpia de seguretat",
"backup_extracting_archive": "Extraient l'arxiu de la còpia de seguretat…",
"backup_hook_unknown": "Script de còpia de seguretat \"{hook:s}\" desconegut",
"backup_invalid_archive": "Arxiu de còpia de seguretat no vàlid",
"backup_method_borg_finished": "La còpia de seguretat a borg ha acabat",
"backup_hook_unknown": "Script de còpia de seguretat «{hook:s}» desconegut",
"backup_invalid_archive": "Aquest no és un arxiu de còpia de seguretat",
"backup_method_borg_finished": "La còpia de seguretat a Borg ha acabat",
"backup_method_copy_finished": "La còpia de la còpia de seguretat ha acabat",
"backup_method_custom_finished": "El mètode de còpia de seguretat personalitzat \"{method:s}\" ha acabat",
"backup_method_tar_finished": "S'ha creat l'arxiu de còpia de seguretat tar",
"backup_method_tar_finished": "S'ha creat l'arxiu de còpia de seguretat TAR",
"backup_mount_archive_for_restore": "Preparant l'arxiu per la restauració…",
"good_practices_about_user_password": "Esteu a punt de definir una nova contrasenya d'usuari. La contrasenya ha de tenir un mínim de 8 caràcters ; tot i que és de bona pràctica utilitzar una contrasenya més llarga (és a dir una frase de contrasenya) i/o utilitzar diferents tipus de caràcters (majúscules, minúscules, dígits i caràcters especials).",
"good_practices_about_user_password": "Esteu a punt de definir una nova contrasenya d'usuari. La contrasenya ha de tenir un mínim de 8 caràcters; tot i que és de bona pràctica utilitzar una contrasenya més llarga (és a dir una frase de contrasenya) i/o utilitzar diferents tipus de caràcters (majúscules, minúscules, dígits i caràcters especials).",
"password_listed": "Aquesta contrasenya és una de les més utilitzades en el món. Si us plau utilitzeu-ne una més única.",
"password_too_simple_1": "La contrasenya ha de tenir un mínim de 8 caràcters",
"password_too_simple_2": "La contrasenya ha de tenir un mínim de 8 caràcters i ha de contenir dígits, majúscules i minúscules",
@ -115,42 +115,42 @@
"password_too_simple_4": "La contrasenya ha de tenir un mínim de 12 caràcters i tenir dígits, majúscules, minúscules i caràcters especials",
"backup_no_uncompress_archive_dir": "El directori de l'arxiu descomprimit no existeix",
"backup_nothings_done": "No hi ha res a guardar",
"backup_output_directory_forbidden": "Directori de sortida no permès. Les còpies de seguretat no es poden crear ni dins els directoris /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ni dins els subdirectoris /home/yunohost.backup/archives",
"backup_output_directory_not_empty": "El directori de sortida no està buit",
"backup_output_directory_forbidden": "Escolliu un directori de sortida different. Les còpies de seguretat no es poden crear ni dins els directoris /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ni dins els subdirectoris /home/yunohost.backup/archives",
"backup_output_directory_not_empty": "Heu d'escollir un directori de sortida buit",
"backup_output_directory_required": "Heu d'especificar un directori de sortida per la còpia de seguretat",
"backup_output_symlink_dir_broken": "Teniu un enllaç simbòlic trencat en lloc del directori dels arxius '{path:s}'. Pot ser teniu una configuració per la còpia de seguretat específica en un altre sistema de fitxers, si és el cas segurament heu oblidat muntar o connectar el disc dur o la clau USB.",
"backup_php5_to_php7_migration_may_fail": "No s'ha pogut convertir l'arxiu per suportar php7, la restauració de les vostres aplicacions pot fallar (raó: {error:s})",
"backup_output_symlink_dir_broken": "El directori del arxiu «{path:s}» es un enllaç simbòlic trencat. Pot ser heu oblidat muntar, tornar a muntar o connectar el mitja d'emmagatzematge al que apunta.",
"backup_php5_to_php7_migration_may_fail": "No s'ha pogut convertir l'arxiu per suportar PHP 7, pot ser que no es puguin restaurar les vostres aplicacions PHP (raó: {error:s})",
"backup_running_hooks": "Executant els scripts de la còpia de seguretat…",
"backup_system_part_failed": "No s'ha pogut fer la còpia de seguretat de la part \"{part:s}\" del sistema",
"backup_unable_to_organize_files": "No s'han pogut organitzar els fitxers dins de l'arxiu amb el mètode ràpid",
"backup_with_no_backup_script_for_app": "L'aplicació {app:s} no té un script de còpia de seguretat. Serà ignorat.",
"backup_with_no_restore_script_for_app": "L'aplicació {app:s} no té un script de restauració, no podreu restaurar automàticament la còpia de seguretat d'aquesta aplicació.",
"certmanager_acme_not_configured_for_domain": "El certificat pel domini {domain:s} sembla que no està instal·lat correctament. Si us plau executeu primer cert-install per aquest domini.",
"certmanager_attempt_to_renew_nonLE_cert": "El certificat pel domini {domain:s} no ha estat emès per Let's Encrypt. No es pot renovar automàticament!",
"certmanager_attempt_to_renew_valid_cert": "El certificat pel domini {domain:s} està a punt de caducar! (Utilitzeu --force si sabeu el que esteu fent)",
"backup_unable_to_organize_files": "No s'ha pogut utilitzar el mètode ràpid per organitzar els fitxers dins de l'arxiu",
"backup_with_no_backup_script_for_app": "L'aplicació «{app:s}» no té un script de còpia de seguretat. Serà ignorat.",
"backup_with_no_restore_script_for_app": "L'aplicació «{app:s}» no té un script de restauració, no podreu restaurar automàticament la còpia de seguretat d'aquesta aplicació.",
"certmanager_acme_not_configured_for_domain": "El certificat pel domini «{domain:s}» sembla que no està instal·lat correctament. Si us plau executeu primer «cert-install» per aquest domini.",
"certmanager_attempt_to_renew_nonLE_cert": "El certificat pel domini «{domain:s}» no ha estat emès per Let's Encrypt. No es pot renovar automàticament!",
"certmanager_attempt_to_renew_valid_cert": "El certificat pel domini «{domain:s}» està a punt de caducar! (Utilitzeu --force si sabeu el que esteu fent)",
"certmanager_attempt_to_replace_valid_cert": "Esteu intentant sobreescriure un certificat correcte i vàlid pel domini {domain:s}! (Utilitzeu --force per ometre)",
"certmanager_cannot_read_cert": "S'ha produït un error al intentar obrir el certificat actual pel domini {domain:s} (arxiu: {file:s}), raó: {reason:s}",
"certmanager_cert_install_success": "S'ha instal·lat correctament un certificat Let's Encrypt pel domini {domain:s}!",
"certmanager_cert_install_success_selfsigned": "S'ha instal·lat correctament un certificat auto-signat pel domini {domain:s}!",
"certmanager_cert_renew_success": "S'ha renovat correctament el certificat Let's Encrypt pel domini {domain:s}!",
"certmanager_cert_install_success": "S'ha instal·lat correctament un certificat Let's Encrypt pel domini «{domain:s}»",
"certmanager_cert_install_success_selfsigned": "S'ha instal·lat correctament un certificat auto-signat pel domini «{domain:s}»",
"certmanager_cert_renew_success": "S'ha renovat correctament el certificat Let's Encrypt pel domini «{domain:s}»",
"certmanager_cert_signing_failed": "No s'ha pogut firmar el nou certificat",
"certmanager_certificate_fetching_or_enabling_failed": "Sembla que l'activació del nou certificat per {domain:s} ha fallat…",
"certmanager_conflicting_nginx_file": "No s'ha pogut preparar el domini per al desafiament ACME: l'arxiu de configuració nginx {filepath:s} entra en conflicte i s'ha d'eliminar primer",
"certmanager_certificate_fetching_or_enabling_failed": "Sembla que utilitzar el nou certificat per {domain:s} ha fallat…",
"certmanager_conflicting_nginx_file": "No s'ha pogut preparar el domini per al desafiament ACME: l'arxiu de configuració NGINX {filepath:s} entra en conflicte i s'ha d'eliminar primer",
"certmanager_couldnt_fetch_intermediate_cert": "S'ha exhaurit el temps d'esperar al intentar recollir el certificat intermedi des de Let's Encrypt. La instal·lació/renovació del certificat s'ha cancel·lat - torneu a intentar-ho més tard.",
"certmanager_domain_cert_not_selfsigned": "El certificat pel domini {domain:s} no és auto-signat Esteu segur de voler canviar-lo? (Utilitzeu --force per fer-ho)",
"certmanager_domain_dns_ip_differs_from_public_ip": "El registre DNS \"A\" pel domini {domain:s} és diferent a l'adreça IP d'aquest servidor. Si heu modificat recentment el registre A, si us plau espereu a que es propagui (hi ha eines per verificar la propagació disponibles a internet). (Si sabeu el que esteu fent, podeu utilitzar --no-checks per desactivar aquestes comprovacions.)",
"certmanager_domain_http_not_working": "Sembla que el domini {domain:s} no és accessible via HTTP. Si us plau verifiqueu que les configuracions DNS i nginx siguin correctes",
"certmanager_domain_cert_not_selfsigned": "El certificat pel domini {domain:s} no és auto-signat Esteu segur de voler canviar-lo? (Utilitzeu «--force» per fer-ho)",
"certmanager_domain_dns_ip_differs_from_public_ip": "El registre DNS \"A\" pel domini «{domain:s}» és diferent a l'adreça IP d'aquest servidor. Si heu modificat recentment el registre A, si us plau espereu a que es propagui (hi ha eines per verificar la propagació disponibles a internet). (Si sabeu el que esteu fent, podeu utilitzar «--no-checks» per desactivar aquestes comprovacions.)",
"certmanager_domain_http_not_working": "Sembla que el domini {domain:s} no és accessible via HTTP. Verifiqueu que les configuracions DNS i NGINX siguin correctes",
"certmanager_domain_not_resolved_locally": "El domini {domain:s} no es pot resoldre dins del vostre servidor YunoHost. Això pot passar si heu modificat recentment el registre DNS. Si és així, si us plau espereu unes hores per a que es propagui. Si el problema continua, considereu afegir {domain:s} a /etc/hosts. (Si sabeu el que esteu fent, podeu utilitzar --no-checks per desactivar aquestes comprovacions.)",
"certmanager_domain_unknown": "Domini desconegut {domain:s}",
"certmanager_error_no_A_record": "No s'ha trobat cap registre DNS \"A\" per {domain:s}. Heu de fer que el vostre nom de domini apunti cap a la vostra màquina per tal de poder instal·lar un certificat Let's Encrypt! (Si sabeu el que esteu fent, podeu utilitzar --no-checks per desactivar aquestes comprovacions.)",
"certmanager_domain_unknown": "Domini desconegut «{domain:s}»",
"certmanager_error_no_A_record": "No s'ha trobat cap registre DNS «A» per «{domain:s}». Heu de fer que el vostre nom de domini apunti cap a la vostra màquina per tal de poder instal·lar un certificat Let's Encrypt. (Si sabeu el que esteu fent, podeu utilitzar «--no-checks» per desactivar aquestes comprovacions.)",
"certmanager_hit_rate_limit": "S'han emès massa certificats recentment per aquest mateix conjunt de dominis {domain:s}. Si us plau torneu-ho a intentar més tard. Consulteu https://letsencrypt.org/docs/rate-limits/ per obtenir més detalls",
"certmanager_http_check_timeout": "S'ha exhaurit el temps d'espera quan el servidor ha intentat contactar amb ell mateix via HTTP utilitzant la seva adreça IP pública (domini domain:s} amb IP {ip:s}). Pot ser degut a hairpinning o a que el talla focs/router al que està connectat el servidor estan mal configurats.",
"certmanager_http_check_timeout": "S'ha exhaurit el temps d'espera quan el servidor ha intentat contactar amb ell mateix via HTTP utilitzant la seva adreça IP pública (domini «{domain:s}» amb IP «{ip:s}»). Pot ser degut a hairpinning o a que el talla focs/router al que està connectat el servidor estan mal configurats.",
"certmanager_no_cert_file": "No s'ha pogut llegir l'arxiu del certificat pel domini {domain:s} (fitxer: {file:s})",
"certmanager_self_ca_conf_file_not_found": "No s'ha trobat el fitxer de configuració per l'autoritat del certificat auto-signat (fitxer: {file:s})",
"certmanager_unable_to_parse_self_CA_name": "No s'ha pogut analitzar el nom de l'autoritat del certificat auto-signat (fitxer: {file:s})",
"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:s}] ",
"confirm_app_install_danger": "ATENCIÓ! Aquesta aplicació encara és experimental (si no és que no funciona directament) i és probable que trenqui el sistema! No hauríeu d'instal·lar-la a no ser que sapigueu el que feu. Esteu segurs de voler córrer aquest risc? [{answers:s}] ",
"confirm_app_install_thirdparty": "ATENCIÓ! La instal·lació d'aplicacions de terceres parts pot comprometre la integritat i seguretat del seu sistema. Faci-ho sota la seva responsabilitat.No hauríeu d'instal·lar-ne a no ser que sapigueu el que feu. Esteu segurs de voler córrer aquest risc? [{answers:s}] ",
"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:s}] ",
"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:s}»",
"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:s}»",
"custom_app_url_required": "Heu de especificar una URL per actualitzar la vostra aplicació personalitzada {app:s}",
"custom_appslist_name_required": "Heu d'especificar un nom per la vostra llista d'aplicacions personalitzada",
"diagnosis_debian_version_error": "No s'ha pogut obtenir la versió Debian: {error}",
@ -158,24 +158,24 @@
"diagnosis_monitor_disk_error": "No es poden monitorar els discs: {error}",
"diagnosis_monitor_network_error": "No es pot monitorar la xarxa: {error}",
"diagnosis_monitor_system_error": "No es pot monitorar el sistema: {error}",
"diagnosis_no_apps": "No hi ha cap aplicació instal·lada",
"diagnosis_no_apps": "Aquesta aplicació no està instal·lada",
"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 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 dpkg --configure -a».",
"dnsmasq_isnt_installed": "sembla que dnsmasq no està instal·lat, executeu \"apt-get remove bind9 && apt-get install dnsmasq\"",
"domain_cannot_remove_main": "No es pot eliminar el domini principal. S'ha d'establir un nou domini primer",
"domain_cert_gen_failed": "No s'ha pogut generar el certificat",
"domain_created": "S'ha creat el domini",
"domain_creation_failed": "No s'ha pogut crear el domini",
"domain_creation_failed": "No s'ha pogut crear el domini {domain}: {error}",
"domain_deleted": "S'ha eliminat el domini",
"domain_deletion_failed": "No s'ha pogut eliminar el domini",
"domain_deletion_failed": "No s'ha pogut eliminar el domini {domini}: {error}",
"domain_exists": "El domini ja existeix",
"app_action_cannot_be_ran_because_required_services_down": "Aquesta aplicació necessita serveis que estan aturats. Abans de continuar, hauríeu d'intentar arrancar de nou els serveis següents (i també investigar perquè estan aturats) : {services}",
"app_action_cannot_be_ran_because_required_services_down": "Aquests serveis necessaris haurien d'estar funcionant per poder executar aquesta acció: {services} Intenteu reiniciar-los per continuar (i possiblement investigar perquè estan aturats).",
"domain_dns_conf_is_just_a_recommendation": "Aquesta ordre mostra la configuració *recomanada*. En cap cas fa la configuració del DNS. És la vostra responsabilitat configurar la zona DNS en el vostre registrar en acord amb aquesta recomanació.",
"domain_dyndns_already_subscribed": "Ja us heu subscrit a un domini DynDNS",
"domain_dyndns_dynette_is_unreachable": "No s'ha pogut abastar la dynette YunoHost, o bé YunoHost no està connectat a internet correctament o bé el servidor dynette està caigut. Error: {error}",
"domain_dyndns_invalid": "Domini no vàlid per utilitzar amb DynDNS",
"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 (no és segur ... 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": "Hi ha una o més aplicacions instal·lades en aquest domini. Desinstal·leu les abans d'eliminar el domini",
"domain_unknown": "Domini desconegut",
"domain_zone_exists": "El fitxer de zona DNS ja existeix",
@ -187,61 +187,61 @@
"dyndns_could_not_check_available": "No s'ha pogut verificar la disponibilitat de {domain:s} a {provider:s}.",
"dyndns_ip_update_failed": "No s'ha pogut actualitzar l'adreça IP al DynDNS",
"dyndns_ip_updated": "S'ha actualitzat l'adreça IP al DynDNS",
"dyndns_key_generating": "S'està generant la clau DNS, això pot trigar una estona…",
"dyndns_key_generating": "S'està generant la clau DNS… això pot trigar una estona.",
"dyndns_key_not_found": "No s'ha trobat la clau DNS pel domini",
"dyndns_no_domain_registered": "No hi ha cap domini registrat amb DynDNS",
"dyndns_registered": "S'ha registrat el domini DynDNS",
"dyndns_registration_failed": "No s'ha pogut registrar el domini DynDNS: {error:s}",
"dyndns_domain_not_provided": "El proveïdor {provider:s} no pot oferir el domini {domain:s}.",
"dyndns_domain_not_provided": "El proveïdor de DynDNS {provider:s} no pot oferir el domini {domain:s}.",
"dyndns_unavailable": "El domini {domain:s} no està disponible.",
"executing_command": "Execució de l'ordre « {command:s} »…",
"executing_script": "Execució de l'script « {script:s} »…",
"extracting": "Extracció en curs…",
"dyndns_cron_installed": "S'ha instal·lat la tasca cron pel DynDNS",
"dyndns_cron_installed": "S'ha creat la tasca cron pel DynDNS",
"dyndns_cron_remove_failed": "No s'ha pogut eliminar la tasca cron per a DynDNS: {error}",
"dyndns_cron_removed": "S'ha eliminat la tasca cron pel DynDNS",
"experimental_feature": "Atenció: aquesta funcionalitat és experimental i no es considera estable, no s'ha d'utilitzar a excepció de saber el que esteu fent.",
"experimental_feature": "Atenció: Aquesta funcionalitat és experimental i no es considera estable, no s'ha d'utilitzar a excepció de saber el que esteu fent.",
"field_invalid": "Camp incorrecte « {:s} »",
"file_does_not_exist": "El camí {path:s} no existeix.",
"firewall_reload_failed": "No s'ha pogut tornar a carregar el tallafoc",
"firewall_reloaded": "S'ha tornat a carregar el tallafoc",
"firewall_rules_cmd_failed": "No s'han pogut aplicar algunes regles del tallafoc. Mireu el registre per a més informació.",
"firewall_reload_failed": "No s'ha pogut tornar a carregar el tallafocs",
"firewall_reloaded": "S'ha tornat a carregar el tallafocs",
"firewall_rules_cmd_failed": "No s'han pogut aplicar algunes regles del tallafocs. Més informació en el registre.",
"format_datetime_short": "%d/%m/%Y %H:%M",
"global_settings_bad_choice_for_enum": "Opció pel paràmetre {setting:s} incorrecta, s'ha rebut «{choice:s}» però les opcions disponibles són: {available_choices:s}",
"global_settings_bad_choice_for_enum": "Opció pel paràmetre {setting:s} incorrecta, s'ha rebut «{choice:s}», però les opcions disponibles són: {available_choices:s}",
"global_settings_bad_type_for_setting": "El tipus del paràmetre {setting:s} és incorrecte. S'ha rebut {received_type:s}, però s'esperava {expected_type:s}",
"global_settings_cant_open_settings": "No s'ha pogut obrir el fitxer de configuració, raó: {reason:s}",
"global_settings_cant_serialize_settings": "No s'ha pogut serialitzar les dades de configuració, raó: {reason:s}",
"global_settings_cant_write_settings": "No s'ha pogut escriure el fitxer de configuració, raó: {reason:s}",
"global_settings_key_doesnt_exists": "La clau « {settings_key:s} » no existeix en la configuració global, podeu veure totes les claus disponibles executant «yunohost settings list »",
"global_settings_reset_success": "Èxit. S'ha fet una còpia de seguretat de la configuració anterior a {path:s}",
"global_settings_reset_success": "S'ha fet una còpia de seguretat de la configuració anterior a {path:s}",
"global_settings_setting_example_bool": "Exemple d'opció booleana",
"global_settings_setting_example_enum": "Exemple d'opció de tipus enumeració",
"global_settings_setting_example_int": "Exemple d'opció de tipus enter",
"global_settings_setting_example_string": "Exemple d'opció de tipus cadena",
"global_settings_setting_security_nginx_compatibility": "Solució de compromís entre compatibilitat i seguretat pel servidor web nginx. Afecta els criptògrafs (i altres aspectes relacionats amb la seguretat)",
"global_settings_setting_security_nginx_compatibility": "Solució de compromís entre compatibilitat i seguretat pel servidor web NGINX. Afecta els criptògrafs (i altres aspectes relacionats amb la seguretat)",
"global_settings_setting_security_password_admin_strength": "Robustesa de la contrasenya d'administrador",
"global_settings_setting_security_password_user_strength": "Robustesa de la contrasenya de l'usuari",
"global_settings_setting_security_ssh_compatibility": "Solució de compromís entre compatibilitat i seguretat pel servidor SSH. Afecta els criptògrafs (i altres aspectes relacionats amb la seguretat)",
"global_settings_unknown_setting_from_settings_file": "Clau de configuració desconeguda: «{setting_key:s}», refusant-la i guardant-la a /etc/yunohost/settings-unknown.json",
"global_settings_unknown_setting_from_settings_file": "Clau de configuració desconeguda: «{setting_key:s}», refusada i guardada a /etc/yunohost/settings-unknown.json",
"global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Permetre la clau d'hoste DSA (obsolet) per la configuració del servei SSH",
"global_settings_unknown_type": "Situació inesperada, la configuració {setting:s} sembla tenir el tipus {unknown_type:s} però no és un tipus reconegut pel sistema.",
"good_practices_about_admin_password": "Esteu a punt de definir una nova contrasenya d'administrador. La contrasenya ha de tenir un mínim de 8 caràcters ; tot i que és de bona pràctica utilitzar una contrasenya més llarga (és a dir una frase de contrasenya) i/o utilitzar diferents tipus de caràcters (majúscules, minúscules, dígits i caràcters especials).",
"hook_exec_failed": "No s'ha pogut executar l'script: {path:s}",
"hook_exec_not_terminated": "L'execució de l'script « {path:s} » no s'ha acabat correctament",
"hook_json_return_error": "No s'ha pogut llegir el retorn de l'script {path:s}. Error: {msg:s}. Contingut en brut: {raw_content}",
"hook_list_by_invalid": "Propietat per llistar les accions invàlida",
"good_practices_about_admin_password": "Esteu a punt de definir una nova contrasenya d'administrador. La contrasenya ha de tenir un mínim de 8 caràcters; tot i que és de bona pràctica utilitzar una contrasenya més llarga (és a dir una frase de contrasenya) i/o utilitzar diferents tipus de caràcters (majúscules, minúscules, dígits i caràcters especials).",
"hook_exec_failed": "No s'ha pogut executar el script: {path:s}",
"hook_exec_not_terminated": "El script no s'ha acabat correctament: {path:s}",
"hook_json_return_error": "No s'ha pogut llegir el retorn del script {path:s}. Error: {msg:s}. Contingut en brut: {raw_content}",
"hook_list_by_invalid": "Aquesta propietat no es pot utilitzar per llistar els hooks",
"hook_name_unknown": "Nom de script « {name:s} »desconegut",
"installation_complete": "Instal·lació completada",
"installation_failed": "Ha fallat la instal·lació",
"installation_failed": "Ha fallat alguna cosa amb la instal·lació",
"invalid_url_format": "Format d'URL invàlid",
"ip6tables_unavailable": "No podeu modificar les ip6tables 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_category_404": "La categoria de registres « {category} » no existeix",
"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 display {name} »",
"log_link_to_failed_log": "L'operació « {dec} » ha fallat! 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": "L'operació « {dec} » ha fallat! Per obtenir ajuda, compartiu el registre complete de l'operació utilitzant l'ordre «yunohost log display {name} --share»",
"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 display {name} --share»",
"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_operation_unit_unclosed_properly": "L'operació no s'ha tancat de forma correcta",
"log_app_addaccess": "Afegir accés a « {} »",
@ -263,7 +263,7 @@
"log_domain_remove": "Elimina el domini « {} » de la configuració del sistema",
"log_dyndns_subscribe": "Subscriure's a un subdomini YunoHost « {} »",
"log_dyndns_update": "Actualitza la IP associada al subdomini YunoHost « {} »",
"log_letsencrypt_cert_install": "Instal·la el certificat Let's Encrypt al domini « {} »",
"log_letsencrypt_cert_install": "Instal·la un certificat Let's Encrypt al domini « {} »",
"log_selfsigned_cert_install": "Instal·la el certificat autosignat al domini « {} »",
"log_letsencrypt_cert_renew": "Renova el certificat Let's Encrypt de « {} »",
"log_service_enable": "Activa el servei « {} »",
@ -278,81 +278,81 @@
"log_tools_upgrade": "Actualitza els paquets del sistema",
"log_tools_shutdown": "Apaga el servidor",
"log_tools_reboot": "Reinicia el servidor",
"already_up_to_date": "No hi ha res a fer! Tot està al dia!",
"already_up_to_date": "No hi ha res a fer. Tot està actualitzat.",
"dpkg_lock_not_available": "No es pot utilitzar aquesta comanda en aquest moment ja que sembla que un altre programa està utilitzant el lock de dpkg (el gestor de paquets del sistema)",
"global_settings_setting_security_postfix_compatibility": "Solució de compromís entre compatibilitat i seguretat pel servidor Postfix. Afecta els criptògrafs (i altres aspectes relacionats amb la seguretat)",
"ldap_init_failed_to_create_admin": "La inicialització de LDAP no ha pogut crear l'usuari admin",
"ldap_initialized": "S'ha iniciat LDAP",
"license_undefined": "indefinit",
"mail_alias_remove_failed": "No s'han pogut eliminar els alias del correu «{mail:s}»",
"mail_domain_unknown": "Domini d'adreça de correu «{domain:s}» desconegut",
"mail_alias_remove_failed": "No s'han pogut eliminar els àlies del correu «{mail:s}»",
"mail_domain_unknown": "El domini «{domain:s}» de l'adreça de correu no és vàlid. Utilitzeu un domini administrat per aquest servidor.",
"mail_forward_remove_failed": "No s'han pogut eliminar el reenviament de correu «{mail:s}»",
"mailbox_used_space_dovecot_down": "S'ha d'engegar el servei de correu Dovecot per poder obtenir l'espai utilitzat per la bústia de correu",
"mail_unavailable": "Aquesta adreça de correu esta reservada i ha de ser atribuïda automàticament el primer usuari",
"mailbox_used_space_dovecot_down": "S'ha d'engegar el servei de correu Dovecot, per poder obtenir l'espai utilitzat per la bústia de correu",
"mail_unavailable": "Aquesta adreça de correu està reservada i ha de ser atribuïda automàticament el primer usuari",
"maindomain_change_failed": "No s'ha pogut canviar el domini principal",
"maindomain_changed": "S'ha canviat el domini principal",
"migrate_tsig_end": "La migració cap a hmac-sha512 s'ha acabat",
"migrate_tsig_failed": "Ha fallat la migració del domini dyndns {domain} cap a hmac-sha512, anul·lant les modificacions. Error: {error_code} - {error}",
"migrate_tsig_start": "L'algoritme de generació de claus no es prou segur per a la signatura TSIG del domini «{domain}», començant la migració cap a un de més segur hmac-sha512",
"migrate_tsig_wait": "Esperar 3 minuts per a que el servidor dyndns tingui en compte la nova clau…",
"migrate_tsig_end": "La migració cap a HMAC-SHA-512 s'ha acabat",
"migrate_tsig_failed": "Ha fallat la migració del domini DynDNS «{domain}» cap a HMAC-SHA-512, anul·lant les modificacions. Error: {error_code}, {error}",
"migrate_tsig_start": "L'algoritme de generació de claus no es prou segur per a la signatura TSIG del domini «{domain}», començant la migració cap a un de més segur HMAC-SHA-512",
"migrate_tsig_wait": "Esperant tres minuts per a que el servidor DynDNS tingui en compte la nova clau…",
"migrate_tsig_wait_2": "2 minuts…",
"migrate_tsig_wait_3": "1 minut…",
"migrate_tsig_wait_4": "30 segons…",
"migrate_tsig_not_needed": "Sembla que no s'utilitza cap domini dyndns, no és necessari fer cap migració!",
"migrate_tsig_not_needed": "Sembla que no s'utilitza cap domini DynDNS, no és necessari fer cap migració.",
"migration_description_0001_change_cert_group_to_sslcert": "Canvia els permisos del grup dels certificats de «metronome»a «ssl-cert»",
"migration_description_0002_migrate_to_tsig_sha256": "Millora la seguretat de dyndns TSIG utilitzant SHA512 en lloc de MD5",
"migration_description_0002_migrate_to_tsig_sha256": "Millora la seguretat de DynDNS TSIG utilitzant SHA-512 en lloc de MD5",
"migration_description_0003_migrate_to_stretch": "Actualització del sistema a Debian Stretch i YunoHost 3.0",
"migration_description_0004_php5_to_php7_pools": "Tornar a configurar els pools PHP per utilitzar PHP 7 en lloc de PHP 5",
"migration_description_0005_postgresql_9p4_to_9p6": "Migració de les bases de dades de postgresql 9.4 a 9.6",
"migration_description_0005_postgresql_9p4_to_9p6": "Migració de les bases de dades de PostgreSQL 9.4 a 9.6",
"migration_description_0006_sync_admin_and_root_passwords": "Sincronitzar les contrasenyes admin i root",
"migration_description_0007_ssh_conf_managed_by_yunohost_step1": "La configuració SSH serà gestionada per YunoHost (pas 1, automàtic)",
"migration_description_0008_ssh_conf_managed_by_yunohost_step2": "La configuració SSH serà gestionada per YunoHost (pas 2, manual)",
"migration_description_0009_decouple_regenconf_from_services": "Desvincula el mecanisme regen-conf dels serveis",
"migration_description_0010_migrate_to_apps_json": "Elimina la appslists (desfasat) i utilitza la nova llista unificada «apps.json» en el seu lloc",
"migration_description_0010_migrate_to_apps_json": "Elimina les llistes d'aplicacions obsoletes i utilitza la nova llista unificada «apps.json» en el seu lloc",
"migration_0003_backward_impossible": "La migració Stretch no és reversible.",
"migration_0003_start": "Ha començat la migració a Stretch. Els registres estaran disponibles a {logfile}.",
"migration_0003_patching_sources_list": "Modificant el fitxer sources.lists…",
"migration_0003_main_upgrade": "Començant l'actualització principal…",
"migration_0003_fail2ban_upgrade": "Començant l'actualització de fail2ban…",
"migration_0003_fail2ban_upgrade": "Començant l'actualització de Fail2Ban…",
"migration_0003_restoring_origin_nginx_conf": "El fitxer /etc/nginx/nginx.conf ha estat editat. La migració el tornarà al seu estat original... El fitxer anterior estarà disponible com a {backup_dest}.",
"migration_0003_yunohost_upgrade": "Començant l'actualització del paquet yunohost... La migració acabarà, però l'actualització actual es farà just després. Després de completar aquesta operació, pot ser que us hagueu de tornar a connectar a la web d'administració.",
"migration_0003_yunohost_upgrade": "Començant l'actualització del paquet YunoHost... La migració acabarà, però l'actualització actual es farà just després. Després de completar aquesta operació, pot ser que us hagueu de tornar a connectar a la web d'administració.",
"migration_0003_not_jessie": "La distribució Debian actual no és Jessie!",
"migration_0003_system_not_fully_up_to_date": "El vostre sistema no està completament actualitzat. S'ha de fer una actualització normal abans de fer la migració a Stretch.",
"migration_0003_still_on_jessie_after_main_upgrade": "Hi ha hagut un problema durant l'actualització principal: el sistema encara està amb Jessie!? Per investigar el problema, mireu el registres a {log}:s…",
"migration_0003_general_warning": "Tingueu en compte que la migració és una operació delicada. Tot i que l'equip de YunoHost a fet els possibles per revisar-la i provar-la, la migració pot provocar errors en parts del sistema o aplicacions.\n\nPer tant, recomanem:\n - Fer una còpia de seguretat de les dades o aplicacions importants. Més informació a https://yunohost.org/backup;\n - Sigueu pacient un cop llençada la migració: en funció de la connexió a internet i el maquinari, pot trigar fins a unes hores per actualitzar-ho tot.\n\nD'altra banda, el port per SMTP, utilitzat per clients de correu externs (com Thunderbird o K9-Mail) ha canviat de 465 (SSL/TLS) a 587 (STARTTLS). L'antic port 465 serà tancat automàticament i el nou port 587 serà obert en el tallafocs. Tots els usuaris *hauran* d'adaptar la configuració dels clients de correu en acord amb aquests canvis!",
"migration_0003_problematic_apps_warning": "Tingueu en compte que s'han detectat les aplicacions, possiblement, problemàtiques següents. Sembla que aquestes no s'han instal·lat des d'una applist o que no estan marcades com a «working». Per conseqüent, no podem garantir que segueixin funcionant després de l'actualització: {problematic_apps}",
"migration_0003_still_on_jessie_after_main_upgrade": "Hi ha hagut un problema durant l'actualització principal: El sistema encara està amb Jessie? Per investigar el problema, mireu el registres a {log}:s…",
"migration_0003_general_warning": "Tingueu en compte que la migració és una operació delicada. L'equip de YunoHost a fet els possibles per revisar-la i provar-la, però la migració pot provocar errors en parts del sistema o aplicacions.\n\nPer tant, es recomana:\n - Fer una còpia de seguretat de les dades o aplicacions importants. Més informació a https://yunohost.org/backup;\n - Sigueu pacient un cop llençada la migració: en funció de la connexió a internet i el maquinari, pot trigar fins a unes hores per actualitzar-ho tot.\n\nD'altra banda, el port per SMTP, utilitzat per clients de correu externs (com Thunderbird o K9-Mail) ha canviat de 465 (SSL/TLS) a 587 (STARTTLS). L'antic port (465) serà tancat automàticament, i el nou port (587) serà obert en el tallafocs. Tots els usuaris *hauran* d'adaptar la configuració dels clients de correu en acord amb aquests canvis.",
"migration_0003_problematic_apps_warning": "Tingueu en compte que s'han detectat les aplicacions, possiblement, problemàtiques següents. Sembla que aquestes no s'han instal·lat des d'una applist, o que no estan marcades com a «working». Per conseqüent, no podem garantir que segueixin funcionant després de l'actualització: {problematic_apps}",
"migration_0003_modified_files": "Tingueu en compte que s'han detectat els següents fitxers que han estat modificats manualment i podrien sobreescriure's al final de l'actualització: {manually_modified_files}",
"migration_0005_postgresql_94_not_installed": "Postgresql no està instal·lat en el sistema. No hi ha res per fer!",
"migration_0005_postgresql_96_not_installed": "S'ha trobat Postgresql 9.4 instal·lat, però no Postgresql 9.6!? Alguna cosa estranya a passat en el sistema :( …",
"migration_0005_not_enough_space": "No hi ha prou espai disponible en {path} per fer la migració en aquest moment :(.",
"migration_0006_disclaimer": "YunoHost esperar que les contrasenyes admin i root estiguin sincronitzades. Fent aquesta migració, la contrasenya root serà reemplaçada per la contrasenya admin.",
"migration_0007_cancelled": "YunoHost no ha pogut millorar la gestió de la configuració SSH.",
"migration_0005_postgresql_94_not_installed": "PostgreSQL no està instal·lat en el sistema. No hi ha res per fer.",
"migration_0005_postgresql_96_not_installed": "PostgreSQL 9.4 està instal·lat, però no PostgreSQL 9.6? Alguna cosa estranya a passat en el sistema :( …",
"migration_0005_not_enough_space": "Creu espai disponible en {path} per executar la migració.",
"migration_0006_disclaimer": "YunoHost esperar que les contrasenyes de admin i root estiguin sincronitzades. Aquesta migració canvia la contrasenya root per la contrasenya admin.",
"migration_0007_cancelled": "No s'ha pogut millorar la gestió de la configuració SSH.",
"migration_0007_cannot_restart": "No es pot reiniciar SSH després d'haver intentat cancel·lar la migració numero 6.",
"migration_0008_general_disclaimer": "Per millorar la seguretat del servidor, es recomana que sigui YunoHost qui gestioni la configuració SSH. La configuració SSH actual és diferent a la configuració recomanada. Si deixeu que YunoHost ho reconfiguri, la manera de connectar-se al servidor mitjançant SSH canviarà de la següent manera:",
"migration_0008_port": " - la connexió es farà utilitzant el port 22 en lloc del port SSH personalitzat actual. Es pot reconfigurar;",
"migration_0008_root": " - no es podrà connectar com a root a través de SSH. S'haurà d'utilitzar l'usuari admin per fer-ho;",
"migration_0008_dsa": " - es desactivarà la clau DSA. Per tant, es podria haver d'invalidar un missatge esgarrifós del client SSH, i tornar a verificar l'empremta digital del servidor;",
"migration_0008_warning": "Si heu entès els avisos i accepteu que YunoHost sobreescrigui la configuració actual, comenceu la migració. Sinó, podeu saltar-vos la migració, tot i que no està recomanat.",
"migration_0008_no_warning": "No s'han detectat riscs importants per sobreescriure la configuració SSH, però no es pot estar del tot segur ;)! Si accepteu que YunoHost sobreescrigui la configuració actual, comenceu la migració. Sinó, podeu saltar-vos la migració, tot i que no està recomanat.",
"migration_0009_not_needed": "Sembla que ja s'ha fet aquesta migració? Ometent.",
"migration_0008_port": "• La connexió es farà utilitzant el port 22 en lloc del port SSH personalitzat actual. Es pot reconfigurar;",
"migration_0008_root": "• No es podrà connectar com a root a través de SSH. S'haurà d'utilitzar l'usuari admin per fer-ho;",
"migration_0008_dsa": "• Es desactivarà la clau DSA. Per tant, es podria haver d'invalidar un missatge esgarrifós del client SSH, i tornar a verificar l'empremta digital del servidor;",
"migration_0008_warning": "Si heu entès els avisos i voleu que YunoHost sobreescrigui la configuració actual, comenceu la migració. Sinó, podeu saltar-vos la migració, tot i que no està recomanat.",
"migration_0008_no_warning": "Hauria de ser segur sobreescriure la configuració SSH, però no es pot estar del tot segur! Executetu la migració per sobreescriure-la. Sinó, podeu saltar-vos la migració, tot i que no està recomanat.",
"migration_0009_not_needed": "Sembla que ja s'ha fet aquesta migració… (?) Ometent.",
"migrations_backward": "Migració cap enrere.",
"migrations_bad_value_for_target": "Nombre invàlid pel paràmetre target, els nombres de migració disponibles són 0 o {}",
"migrations_cant_reach_migration_file": "No s'ha pogut accedir als fitxers de migració al camí %s",
"migrations_cant_reach_migration_file": "No s'ha pogut accedir als fitxers de migració al camí «%s»",
"migrations_current_target": "La migració objectiu és {}",
"migrations_error_failed_to_load_migration": "ERROR: no s'ha pogut carregar la migració {number} {name}",
"migrations_forward": "Migració endavant",
"migrations_list_conflict_pending_done": "No es pot utilitzar --previous i --done al mateix temps.",
"migrations_loading_migration": "Carregant la migració {number} {name}…",
"migrations_migration_has_failed": "La migració {number} {name} ha fallat amb l'excepció {exception}, cancel·lant",
"migrations_list_conflict_pending_done": "No es pot utilitzar «--previous» i «--done» al mateix temps.",
"migrations_loading_migration": "Carregant la migració {id}…",
"migrations_migration_has_failed": "La migració {id} ha fallat, cancel·lant. Error: {exception}",
"migrations_no_migrations_to_run": "No hi ha cap migració a fer",
"migrations_show_currently_running_migration": "Fent la migració {number} {name}…",
"migrations_show_last_migration": "L'última migració feta és {}",
"migrations_skip_migration": "Saltant migració {number} {name}…",
"migrations_skip_migration": "Saltant migració {id}…",
"migrations_success": "S'ha completat la migració {number} {name} amb èxit!",
"migrations_to_be_ran_manually": "La migració {number} {name} s'ha de fer manualment. Aneu a Eines > Migracions a la interfície admin, o executeu «yunohost tools migrations migrate».",
"migrations_need_to_accept_disclaimer": "Per fer la migració {number} {name}, heu d'acceptar aquesta clàusula de no responsabilitat:\n---\n{disclaimer}\n---\nSi accepteu fer la migració, torneu a executar l'ordre amb l'opció --accept-disclaimer.",
"monitor_disabled": "El monitoratge del servidor ha estat desactivat",
"monitor_enabled": "El monitoratge del servidor ha estat activat",
"migrations_to_be_ran_manually": "La migració {id} s'ha de fer manualment. Aneu a Eines → Migracions a la interfície admin, o executeu «yunohost tools migrations migrate».",
"migrations_need_to_accept_disclaimer": "Per fer la migració {id}, heu d'acceptar aquesta clàusula de no responsabilitat:\n---\n{disclaimer}\n---\nSi accepteu fer la migració, torneu a executar l'ordre amb l'opció «--accept-disclaimer».",
"monitor_disabled": "S'ha desactivat el monitoratge del servidor",
"monitor_enabled": "S'ha activat el monitoratge del sistema",
"monitor_glances_con_failed": "No s'ha pogut connectar al servidor Glances",
"monitor_not_enabled": "El monitoratge del servidor no està activat",
"monitor_period_invalid": "Període de temps invàlid",
@ -384,18 +384,18 @@
"pattern_firstname": "Ha de ser un nom vàlid",
"pattern_lastname": "Ha de ser un cognom vàlid",
"pattern_listname": "Ha d'estar compost per caràcters alfanumèrics i guió baix exclusivament",
"pattern_mailbox_quota": "Ha de ser una mida amb el sufix b/k/M/G/T o 0 per desactivar la 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_port": "Ha de ser un número de port vàlid (i.e. 0-65535)",
"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_password_app": "Les contrasenyes no haurien 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:d} ja està tancat per les connexions {ip_version:s}",
"port_already_opened": "El port {port:d} ja està obert per les connexions {ip_version:s}",
"port_available": "El port {port:d} està disponible",
"port_unavailable": "El port {port:d} no està disponible",
"recommend_to_add_first_user": "La post instal·lació s'ha acabat, però YunoHost necessita com a mínim un usuari per funcionar correctament, hauríeu d'afegir un usuari executant «yunohost user create $username» o amb la interfície d'administració.",
"recommend_to_add_first_user": "La post instal·lació s'ha acabat, però YunoHost necessita com a mínim un usuari per funcionar correctament, hauríeu d'afegir un usuari executant «yunohost user create <username>»; o fer-ho des de la interfície d'administració.",
"regenconf_file_backed_up": "S'ha guardat una còpia de seguretat del fitxer de configuració «{conf}» a «{backup}»",
"regenconf_file_copy_failed": "No s'ha pogut copiar el nou fitxer de configuració «{new}» a «{conf}»",
"regenconf_file_kept_back": "S'espera que el fitxer de configuració «{conf}» sigui suprimit per regen-conf (categoria {category}) però s'ha mantingut.",
@ -406,26 +406,26 @@
"regenconf_file_updated": "El fitxer de configuració «{conf}» ha estat actualitzat",
"regenconf_now_managed_by_yunohost": "El fitxer de configuració «{conf}» serà gestionat per YunoHost a partir d'ara (categoria {category}).",
"regenconf_up_to_date": "La configuració ja està al dia per la categoria «{category}»",
"regenconf_updated": "La configuració ha estat actualitzada per la categoria «{category}»",
"regenconf_updated": "La configuració per la categoria «{category}» ha estat actualitzada",
"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_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}»…",
"restore_action_required": "S'ha d'especificar quelcom a restaurar",
"restore_already_installed_app": "Ja hi ha una aplicació instal·lada amb l'id «{app:s}»",
"restore_already_installed_app": "Una aplicació amb la ID «{app:s}» ja està instal·lada",
"restore_app_failed": "No s'ha pogut restaurar l'aplicació «{app:s}»",
"restore_cleaning_failed": "No s'ha pogut netejar el directori temporal de restauració",
"restore_complete": "Restauració completada",
"restore_confirm_yunohost_installed": "Esteu segur de voler restaurar un sistema ja instal·lat? [{answers:s}]",
"restore_extracting": "Extracció dels fitxers necessaris de l'arxiu…",
"restore_failed": "No s'ha pogut restaurar el sistema",
"restore_hook_unavailable": "L'script de restauració «{part:s}» 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 disc (espai lliure: {free_space:d} B, espai necessari: {needed_space:d} B, marge de seguretat: {margin:d} B)",
"restore_hook_unavailable": "El script de restauració «{part:s}» 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:d} B, espai necessari: {needed_space:d} B, marge de seguretat: {margin:d} B)",
"restore_mounting_archive": "Muntatge de l'arxiu a «{path:s}»",
"restore_not_enough_disk_space": "No hi ha prou espai disponible en el disc (espai lliure: {free_space:d} B, espai necessari: {needed_space:d} B, marge de seguretat: {margin:d} B)",
"restore_not_enough_disk_space": "No hi ha prou espai disponible (espai: {free_space:d} B, espai necessari: {needed_space:d} B, marge de seguretat: {margin:d} B)",
"restore_nothings_done": "No s'ha restaurat res",
"restore_removing_tmp_dir_failed": "No s'ha pogut eliminar un directori temporal antic",
"restore_running_app_script": "Execució de l'script de restauració de l'aplicació «{app:s}»…",
"restore_running_app_script": "Restaurant l'aplicació «{app:s}»…",
"restore_running_hooks": "Execució dels hooks de restauració…",
"restore_system_part_failed": "No s'ha pogut restaurar la part «{part:s}» del sistema",
"root_password_desynchronized": "S'ha canviat la contrasenya d'administració, però YunoHost no ha pogut propagar-ho cap a la contrasenya root!",
@ -436,31 +436,31 @@
"server_reboot_confirm": "Es reiniciarà el servidor immediatament, n'esteu segur? [{answers:s}]",
"service_add_failed": "No s'ha pogut afegir el servei «{service:s}»",
"service_added": "S'ha afegit el servei «{service:s}»",
"service_already_started": "Ja s'ha iniciat el servei «{service:s}»",
"service_already_started": "El servei «{service:s}» ja està funcionant",
"service_already_stopped": "Ja s'ha aturat el servei «{service:s}»",
"service_cmd_exec_failed": "No s'ha pogut executar l'ordre «{command:s}»",
"service_description_avahi-daemon": "permet accedir al servidor via yunohost.local en la xarxa local",
"service_description_dnsmasq": "gestiona la resolució del nom de domini (DNS)",
"service_description_dovecot": "permet als clients de correu accedir/recuperar correus (via IMAP i POP3)",
"service_description_fail2ban": "protegeix contra els atacs de força bruta i a altres atacs provinents d'Internet",
"service_description_glances": "monitora la informació del sistema en el servidor",
"service_description_metronome": "gestiona els comptes de missatgeria instantània XMPP",
"service_description_mysql": "guarda les dades de les aplicacions (base de dades SQL)",
"service_description_nginx": "serveix o permet l'accés a totes les pàgines web allotjades en el servidor",
"service_description_nslcd": "gestiona les connexions shell dels usuaris YunoHost",
"service_description_php7.0-fpm": "executa les aplicacions escrites en PHP amb nginx",
"service_description_postfix": "utilitzat per enviar i rebre correus",
"service_description_redis-server": "una base de dades especialitzada per l'accés ràpid a dades, files d'espera i comunicació entre programes",
"service_description_rmilter": "verifica diferents paràmetres en els correus",
"service_description_rspamd": "filtra el correu brossa, i altres funcionalitats relacionades al correu",
"service_description_slapd": "guarda el usuaris, dominis i informació relacionada",
"service_description_ssh": "permet la connexió remota al servidor via terminal (protocol SSH)",
"service_description_yunohost-api": "gestiona les interaccions entre la interfície web de YunoHost i el sistema",
"service_description_yunohost-firewall": "gestiona els ports de connexió oberts i tancats als serveis",
"service_description_avahi-daemon": "Permet accedir al servidor via «yunohost.local» en la xarxa local",
"service_description_dnsmasq": "Gestiona la resolució del nom de domini (DNS)",
"service_description_dovecot": "Permet als clients de correu accedir/recuperar correus (via IMAP i POP3)",
"service_description_fail2ban": "Protegeix contra els atacs de força bruta i a altres atacs provinents d'Internet",
"service_description_glances": "Monitora la informació del sistema en el servidor",
"service_description_metronome": "Gestiona els comptes de missatgeria instantània XMPP",
"service_description_mysql": "Guarda les dades de les aplicacions (base de dades SQL)",
"service_description_nginx": "Serveix o permet l'accés a totes les pàgines web allotjades en el servidor",
"service_description_nslcd": "Gestiona les connexions shell dels usuaris YunoHost",
"service_description_php7.0-fpm": "Executa les aplicacions escrites en PHP amb NGINX",
"service_description_postfix": "Utilitzat per enviar i rebre correus",
"service_description_redis-server": "Una base de dades especialitzada per l'accés ràpid a dades, files d'espera i comunicació entre programes",
"service_description_rmilter": "Verifica diferents paràmetres en els correus",
"service_description_rspamd": "Filtra el correu brossa, i altres funcionalitats relacionades amb el correu",
"service_description_slapd": "Guarda el usuaris, dominis i informació relacionada",
"service_description_ssh": "Permet la connexió remota al servidor via terminal (protocol SSH)",
"service_description_yunohost-api": "Gestiona les interaccions entre la interfície web de YunoHost i el sistema",
"service_description_yunohost-firewall": "Gestiona els ports de connexió oberts i tancats als serveis",
"service_disable_failed": "No s'han pogut deshabilitar el servei «{service:s}»\n\nRegistres recents: {logs:s}",
"service_disabled": "S'ha deshabilitat el servei {service:s}",
"service_disabled": "S'ha deshabilitat el servei «{service:s}»",
"service_enable_failed": "No s'ha pogut activar el servei «{service:s}»\n\nRegistres recents: {log:s}",
"service_enabled": "S'ha activat el servei {service:s}",
"service_enabled": "S'ha activat el servei «{service:s}»",
"service_no_log": "No hi ha cap registre pel servei «{service:s}»",
"service_regen_conf_is_deprecated": "«yunohost service regen-conf» està desfasat! Utilitzeu «yunohost tools regen-conf» en el seu lloc.",
"service_remove_failed": "No s'ha pogut eliminar el servei «{service:s}»",
@ -479,26 +479,26 @@
"service_unknown": "Servei «{service:s}» desconegut",
"ssowat_conf_generated": "S'ha generat la configuració SSOwat",
"ssowat_conf_updated": "S'ha actualitzat la configuració SSOwat",
"ssowat_persistent_conf_read_error": "Error en llegir la configuració persistent de SSOwat: {error:s}. Modifiqueu el fitxer /etc/ssowat/conf.json.persistent per arreglar la sintaxi JSON",
"ssowat_persistent_conf_write_error": "Error guardant la configuració persistent de SSOwat: {error:s}. Modifiqueu el fitxer /etc/ssowat/conf.json.persistent per arreglar la sintaxi JSON",
"ssowat_persistent_conf_read_error": "No s'ha pogut llegir la configuració persistent de SSOwat: {error:s}. Modifiqueu el fitxer /etc/ssowat/conf.json.persistent per arreglar la sintaxi JSON",
"ssowat_persistent_conf_write_error": "No s'ha pogut guardar la configuració persistent de SSOwat: {error:s}. Modifiqueu el fitxer /etc/ssowat/conf.json.persistent per arreglar la sintaxi JSON",
"system_upgraded": "S'ha actualitzat el sistema",
"system_username_exists": "El nom d'usuari ja existeix en els 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 dpkg --configure -a».",
"tools_upgrade_at_least_one": "Especifiqueu --apps O --system",
"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 dpkg --configure -a».",
"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_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_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_special_packages": "Actualitzant els paquets «especials» (relacionats amb YunoHost)…",
"tools_upgrade_special_packages_explanation": "Aquesta acció s'acabarà, però l'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). Un cop acabat, 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 amb «yunohost log list» (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",
"tools_upgrade_special_packages_explanation": "Aquesta acció s'acabarà, però l'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). Un cop acabat, 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 amb «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",
"unbackup_app": "L'aplicació «{app:s}» no serà guardada",
"unexpected_error": "Hi ha hagut un error inesperat: {error}",
"unit_unknown": "Unitat desconeguda «{unit:s}»",
"unlimit": "Sense quota",
"unrestore_app": "L'aplicació «{app:s} no serà restaurada",
"update_apt_cache_failed": "No s'ha pogut actualitzar la memòria cau d'APT (el gestor de paquets de Debian). Aquí teniu les línies de sources.list que poden ajudar-vos a identificar les línies problemàtiques:\n{sourceslist}",
"update_apt_cache_failed": "No s'ha pogut actualitzar la memòria cau d'APT (el gestor de paquets de Debian). Aquí teniu les línies de sources.list, que poden ajudar-vos a identificar les línies problemàtiques:\n{sourceslist}",
"update_apt_cache_warning": "Hi ha hagut errors al actualitzar la memòria cau d'APT (el gestor de paquets de Debian). Aquí teniu les línies de sources.list que poden ajudar-vos a identificar les línies problemàtiques:\n{sourceslist}",
"updating_apt_cache": "Obtenció de les actualitzacions disponibles per als paquets del sistema…",
"updating_app_lists": "Obtenció de les actualitzacions disponibles per a les aplicacions…",
@ -507,23 +507,23 @@
"upnp_dev_not_found": "No s'ha trobat cap dispositiu UPnP",
"upnp_disabled": "S'ha desactivat UPnP",
"upnp_enabled": "S'ha activat UPnP",
"upnp_port_open_failed": "No s'han pogut obrir els ports UPnP",
"upnp_port_open_failed": "No s'ha pogut obrir el port UPnP",
"user_created": "S'ha creat l'usuari",
"user_creation_failed": "No s'ha pogut crear l'usuari",
"user_creation_failed": "No s'ha pogut crear l'usuari {user}: {error}",
"user_deleted": "S'ha suprimit l'usuari",
"user_deletion_failed": "No s'ha pogut suprimir l'usuari",
"user_home_creation_failed": "No s'ha pogut crear la carpeta personal («home») de l'usuari",
"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_info_failed": "No s'ha pogut obtenir la informació de l'usuari",
"user_unknown": "Usuari desconegut: {user:s}",
"user_update_failed": "No s'ha pogut actualitzar l'usuari",
"user_updated": "S'ha actualitzat l'usuari",
"user_update_failed": "No s'ha pogut actualitzar l'usuari {user}: {error}",
"user_updated": "S'ha canviat la informació de l'usuari",
"users_available": "Usuaris disponibles:",
"yunohost_already_installed": "YunoHost ja està instal·lat",
"yunohost_ca_creation_failed": "No s'ha pogut crear l'autoritat de certificació",
"yunohost_ca_creation_success": "S'ha creat l'autoritat de certificació local.",
"yunohost_configured": "S'ha configurat YunoHost",
"yunohost_configured": "YunoHost està configurat",
"yunohost_installing": "Instal·lació de YunoHost…",
"yunohost_not_installed": "YunoHost no està instal·lat o no està instal·lat correctament. Executeu «yunohost tools postinstall»",
"yunohost_not_installed": "YunoHost no està instal·lat correctament. Executeu «yunohost tools postinstall»",
"apps_permission_not_found": "No s'ha trobat cap permís per les aplicacions instal·lades",
"apps_permission_restoration_failed": "Ha fallat el permís «{permission:s}» per la restauració de l'aplicació {app:s}",
"backup_permission": "Permís de còpia de seguretat per l'aplicació {app:s}",
@ -534,14 +534,14 @@
"group_already_disallowed": "El grup «{group:s}» ja té els permisos «{permission:s}» desactivats per l'aplicació «{app:s}»",
"group_name_already_exist": "El grup {name:s} ja existeix",
"group_created": "S'ha creat el grup «{group}»",
"group_creation_failed": "No s'ha pogut crear el grup «{group}»",
"group_creation_failed": "No s'ha pogut crear el grup «{group}»: {error}",
"group_deleted": "S'ha eliminat el grup «{group}»",
"group_deletion_failed": "No s'ha pogut eliminar el grup «{group}»",
"group_deletion_failed": "No s'ha pogut eliminar el grup «{group}»: {error}",
"group_deletion_not_allowed": "El grup {group:s} no es pot eliminar manualment.",
"group_info_failed": "Ha fallat la informació del grup",
"group_unknown": "Grup {group:s} desconegut",
"group_updated": "S'ha actualitzat el grup «{group}»",
"group_update_failed": "No s'ha pogut actualitzat el grup «{group}»",
"group_update_failed": "No s'ha pogut actualitzat el grup «{group}»: {error}",
"log_permission_add": "Afegir el permís «{}» per l'aplicació «{}»",
"log_permission_remove": "Suprimir el permís «{}»",
"log_permission_update": "Actualitzar el permís «{}» per l'aplicació «{}»",
@ -550,31 +550,31 @@
"log_user_group_update": "Actualitzar grup «{}»",
"log_user_permission_add": "Actualitzar el permís «{}»",
"log_user_permission_remove": "Actualitzar el permís «{}»",
"mailbox_disabled": "La bústia de correu està desactivada per als usuaris {user:s}",
"mailbox_disabled": "La bústia de correu està desactivada per al usuari {user:s}",
"migration_description_0011_setup_group_permission": "Configurar el grup d'usuaris i els permisos per les aplicacions i els serveis",
"migration_0011_backup_before_migration": "Creant una còpia de seguretat de la base de dades LDAP i la configuració de les aplicacions abans d'efectuar la migració.",
"migration_0011_can_not_backup_before_migration": "No s'ha pogut fer la còpia de seguretat abans de la migració. No s'ha pogut fer la migració. Error: {error:s}",
"migration_0011_can_not_backup_before_migration": "No s'ha pogut completar la còpia de seguretat abans de que la migració fallés. Error: {error:s}",
"migration_0011_create_group": "Creant un grup per a cada usuari…",
"migration_0011_done": "Migració completa. Ja podeu gestionar grups d'usuaris.",
"migration_0011_LDAP_config_dirty": "Sembla que heu modificat manualment la configuració LDAP. Per fer aquesta migració s'ha d'actualitzar la configuració LDAP.\nGuardeu la configuració actual, reinicieu la configuració original amb l'ordre «yunohost tools regen-conf -f» i torneu a intentar la migració",
"migration_0011_done": "Migració completada. Ja podeu gestionar grups d'usuaris.",
"migration_0011_LDAP_config_dirty": "Sembla que heu modificat manualment la configuració LDAP. Per fer aquesta migració s'ha d'actualitzar la configuració LDAP.\nGuardeu la configuració actual, reinicieu la configuració original executant l'ordre «yunohost tools regen-conf -f» i torneu a intentar la migració",
"migration_0011_LDAP_update_failed": "Ha fallat l'actualització de LDAP. Error: {error:s}",
"migration_0011_migrate_permission": "Fent la migració dels permisos de la configuració de les aplicacions a LDAP…",
"migration_0011_migration_failed_trying_to_rollback": "La migració ha fallat … s'intenta tornar el sistema a l'estat anterior.",
"migration_0011_migration_failed_trying_to_rollback": "No s'ha pogut fer la migració… s'intenta tornar el sistema a l'estat anterior.",
"migration_0011_rollback_success": "S'ha tornat el sistema a l'estat anterior.",
"migration_0011_update_LDAP_database": "Actualitzant la base de dades LDAP…",
"migration_0011_update_LDAP_schema": "Actualitzant l'esquema LDAP…",
"need_define_permission_before": "Heu de tornar a redefinir els permisos utilitzant «yunohost user permission add -u USER» abans d'eliminar un grup permès",
"permission_already_clear": "Ja s'ha donat el permís «{permission:s}» per l'aplicació {app:s}",
"permission_already_exist": "El permís «{permission:s}» ja existeix per l'aplicació {app:s}",
"permission_created": "S'ha creat el permís «{permission:s}» per l'aplicació {app:s}",
"permission_creation_failed": "La creació del permís ha fallat",
"permission_deleted": "S'ha eliminat el permís «{permission:s}» per l'aplicació {app:s}",
"permission_deletion_failed": "L'eliminació del permís «{permission:s}» per l'aplicació {app:s} ha fallat",
"permission_not_found": "No s'ha trobat el permís «{permission:s}» per l'aplicació {app:s}",
"permission_already_exist": "El permís «{permission:s}» ja existeix",
"permission_created": "S'ha creat el permís «{permission:s}»",
"permission_creation_failed": "No s'ha pogut crear el permís «{permission}»: {error}",
"permission_deleted": "S'ha eliminat el permís «{permission:s}»",
"permission_deletion_failed": "No s'ha pogut eliminar el permís «{permission:s}»: {error}",
"permission_not_found": "No s'ha trobat el permís «{permission:s}»",
"permission_name_not_valid": "El nom del permís «{permission:s}» no és vàlid",
"permission_update_failed": "L'actualització del permís ha fallat",
"permission_update_failed": "No s'ha pogut actualitzar el permís «{permission}»: {error}",
"permission_generated": "S'ha actualitzat la base de dades del permís",
"permission_updated": "S'ha actualitzat el permís «{permission:s}» per l'aplicació {app:s}",
"permission_updated": "S'ha actualitzat el permís «{permission:s}»",
"permission_update_nothing_to_do": "No hi ha cap permís per actualitzar",
"remove_main_permission_not_allowed": "No es pot eliminar el permís principal",
"remove_user_of_group_not_allowed": "No es pot eliminar l'usuari {user:s} del grup {group:s}",
@ -582,5 +582,49 @@
"tools_update_failed_to_app_fetchlist": "No s'ha pogut actualitzar la llista d'aplicacions de YunoHost a causa de: {error}",
"user_already_in_group": "L'usuari {user:s} ja és en el grup {group:s}",
"user_not_in_group": "L'usuari {user:s} no és en el grup {group:s}",
"migration_description_0012_postgresql_password_to_md5_authentication": "Força l'autenticació postgresql a fer servir md5 per a les connexions locals"
"migration_description_0012_postgresql_password_to_md5_authentication": "Força l'autenticació PostgreSQL a fer servir MD5 per a les connexions locals",
"app_full_domain_unavailable": "Aquesta aplicació ha de ser instal·lada en el seu propi domini, però ja hi ha altres aplicacions instal·lades en el domini «{domain}». Podeu utilitzar un subdomini dedicat a aquesta aplicació.",
"migrations_not_pending_cant_skip": "Aquestes migracions no estan pendents, així que no poden ser omeses: {ids}",
"app_action_broke_system": "Aquesta acció sembla haver trencat els següents serveis importants: {services}",
"log_permission_urls": "Actualitzar les URLs relacionades amb el permís «{}»",
"log_user_group_create": "Crear grup «{}»",
"log_user_permission_update": "Actualitzar els accessos per al permís «{}»",
"log_user_permission_reset": "Restablir el permís «{}»",
"permission_already_disallowed": "El grup «{group}» ja té el permís «{permission}» desactivat",
"migrations_already_ran": "Aquestes migracions ja s'han fet: {ids}",
"migrations_dependencies_not_satisfied": "Executeu aquestes migracions: «{dependencies_id}», abans la migració {id}.",
"migrations_failed_to_load_migration": "No s'ha pogut carregar la migració {id}: {error}",
"migrations_exclusive_options": "«--auto», «--skip», i «--force-rerun» són opcions mútuament excloents.",
"migrations_must_provide_explicit_targets": "Heu de proporcionar objectius explícits al utilitzar «--skip» o «--force-rerun»",
"migrations_no_such_migration": "No hi ha cap migració anomenada «{id}»",
"migrations_pending_cant_rerun": "Aquestes migracions encara estan pendents, així que no es poden tornar a executar: {ids}",
"migrations_running_forward": "Executant la migració {id}…",
"migrations_success_forward": "Migració {id} completada",
"apps_already_up_to_date": "Ja estan actualitzades totes les aplicacions",
"dyndns_provider_unreachable": "No s'ha pogut connectar amb el proveïdor Dyndns {provider}: o el vostre YunoHost no està ben connectat a Internet o el servidor dynette està caigut.",
"operation_interrupted": "S'ha interromput manualment l'operació?",
"group_already_exist": "El grup {group} ja existeix",
"group_already_exist_on_system": "El grup {group} ja existeix en els grups del sistema",
"group_cannot_be_edited": "El grup {group} no es pot editar manualment.",
"group_cannot_be_deleted": "El grup {group} no es pot eliminar manualment.",
"group_user_already_in_group": "L'usuari {user} ja està en el grup {group}",
"group_user_not_in_group": "L'usuari {user} no està en el grup {group}",
"log_permission_create": "Crear el permís «{}»",
"log_permission_delete": "Eliminar el permís «{}»",
"migration_0011_failed_to_remove_stale_object": "No s'ha pogut eliminar l'objecte obsolet {dn}: {error}",
"permission_already_allowed": "El grup «{group}» ja té el permís «{permission}» activat",
"permission_cannot_remove_main": "No es permet eliminar un permís principal",
"user_already_exists": "L'usuari «{user}» ja existeix",
"app_upgrade_stopped": "S'ha aturat l'actualització de totes les aplicacions per prevenir possibles danys ja que no s'ha pogut actualitzar una aplicació",
"app_install_failed": "No s'ha pogut instal·lar {app}: {error}",
"app_install_script_failed": "Hi ha hagut un error en el script d'instal·lació de l'aplicació",
"group_cannot_edit_all_users": "El grup «all_users» no es pot editar manualment. És un grup especial destinat a contenir els usuaris registrats a YunoHost",
"group_cannot_edit_visitors": "El grup «visitors» no es pot editar manualment. És un grup especial que representa els visitants anònims",
"group_cannot_edit_primary_group": "El grup «{group}» no es pot editar manualment. És el grup principal destinat a contenir un usuari específic.",
"log_permission_url": "Actualització de la URL associada al permís «{}»",
"migration_0011_slapd_config_will_be_overwritten": "Sembla que heu modificat manualment la configuració de sldap. Per aquesta migració crítica, YunoHost ha de forçar l'actualització de la configuració sldap. Es farà una còpia de seguretat a {conf_backup_folder}.",
"permission_already_up_to_date": "No s'ha actualitzat el permís perquè la petició d'afegir/eliminar ja corresponent a l'estat actual.",
"permission_currently_allowed_for_visitors": "El permís ja el tenen el grup de visitants a més d'altres grups. Segurament s'hauria de revocar el permís al grup dels visitants o eliminar els altres grups als que s'ha atribuït.",
"permission_currently_allowed_for_all_users": "El permís ha el té el grup de tots els usuaris (all_users) a més d'altres grups. Segurament s'hauria de revocar el permís a «all_users» o eliminar els altres grups als que s'ha atribuït.",
"permission_require_account": "El permís {permission} només té sentit per als usuaris que tenen un compte, i per tant no es pot activar per als visitants."
}

View file

@ -2,27 +2,27 @@
"action_invalid": "Ungültige Aktion '{action:s}'",
"admin_password": "Administrator-Passwort",
"admin_password_change_failed": "Passwort kann nicht geändert werden",
"admin_password_changed": "Das Administrator-Kennwort wurde erfolgreich geändert",
"admin_password_changed": "Das Administrator-Kennwort wurde geändert",
"app_already_installed": "{app:s} ist schon installiert",
"app_argument_choice_invalid": "Ungültige Auswahl für Argument '{name:s}'. Es muss einer der folgenden Werte sein {choices:s}",
"app_argument_invalid": "Das Argument '{name:s}' hat einen falschen Wert: {error:s}",
"app_argument_choice_invalid": "Wähle einen der folgenden Werte '{choices:s}' für das Argument '{name:s}'",
"app_argument_invalid": "Wähle einen gültigen Wert für das Argument '{name: s}': {error: s}",
"app_argument_required": "Argument '{name:s}' wird benötigt",
"app_extraction_failed": "Installationsdateien konnten nicht entpackt werden",
"app_id_invalid": "Falsche App-ID",
"app_install_files_invalid": "Ungültige Installationsdateien",
"app_location_already_used": "Eine andere App ({app}) ist bereits an diesem Ort ({path}) installiert",
"app_location_install_failed": "Die App kann nicht an diesem Ort installiert werden, da es mit der App {other_app} die bereits in diesem Pfad ({other_path}) installiert ist Probleme geben würde",
"app_manifest_invalid": "Ungültiges App-Manifest: {error}",
"app_no_upgrade": "Keine Aktualisierungen für Apps verfügbar",
"app_not_installed": "{app:s} ist nicht installiert",
"app_install_files_invalid": "Diese Dateien können nicht installiert werden",
"app_location_already_used": "Die App ({app}) ist bereits hier ({path}) installiert",
"app_location_install_failed": "Die App kann dort nicht installiert werden, da ein Konflikt mit der App '{other_app}' besteht, die bereits in '{other_path}' installiert ist",
"app_manifest_invalid": "Mit dem App-Manifest stimmt etwas nicht: {error}",
"app_no_upgrade": "Alle Apps sind bereits aktuell",
"app_not_installed": "Die App {app:s} konnte nicht in der Liste installierter Apps gefunden werden: {all_apps}",
"app_recent_version_required": "Für {:s} benötigt eine aktuellere Version von moulinette",
"app_removed": "{app:s} wurde erfolgreich entfernt",
"app_sources_fetch_failed": "Quelldateien konnten nicht abgerufen werden",
"app_removed": "{app:s} wurde entfernt",
"app_sources_fetch_failed": "Quelldateien konnten nicht abgerufen werden, ist die URL korrekt?",
"app_unknown": "Unbekannte App",
"app_upgrade_failed": "{app:s} konnte nicht aktualisiert werden",
"app_upgraded": "{app:s} wurde erfolgreich aktualisiert",
"appslist_fetched": "Appliste {appslist:s} wurde erfolgreich heruntergelanden",
"appslist_removed": "Appliste {appslist:s} wurde erfolgreich entfernt",
"app_upgraded": "{app:s} aktualisiert",
"appslist_fetched": "Appliste {appslist:s} wurde erfolgreich gelanden",
"appslist_removed": "Appliste {appslist:s} wurde entfernt",
"appslist_retrieve_error": "Entfernte Appliste {appslist:s} kann nicht empfangen werden: {error:s}",
"appslist_unknown": "Appliste {appslist:s} ist unbekannt.",
"ask_current_admin_password": "Derzeitiges Administrator-Kennwort",
@ -34,26 +34,26 @@
"ask_new_admin_password": "Neues Verwaltungskennwort",
"ask_password": "Passwort",
"backup_action_required": "Du musst etwas zum Speichern auswählen",
"backup_app_failed": "Konnte keine Sicherung für '{app:s}' erstellen",
"backup_app_failed": "Konnte keine Sicherung für die App '{app:s}' erstellen",
"backup_archive_app_not_found": "App '{app:s}' konnte in keiner Datensicherung gefunden werden",
"backup_archive_hook_not_exec": "Hook '{hook:s}' konnte für diese Datensicherung nicht ausgeführt werden",
"backup_archive_name_exists": "Datensicherung mit dem selben Namen existiert bereits",
"backup_archive_name_exists": "Datensicherung mit dem selben Namen existiert bereits.",
"backup_archive_name_unknown": "Unbekanntes lokale Datensicherung mit Namen '{name:s}' gefunden",
"backup_archive_open_failed": "Kann Sicherungsarchiv nicht öfnen",
"backup_cleaning_failed": "Temporäres Sicherungsverzeichnis konnte nicht geleert werden",
"backup_created": "Datensicherung komplett",
"backup_creating_archive": "Datensicherung wird erstellt...",
"backup_creating_archive": "Datensicherung wird erstellt",
"backup_delete_error": "Pfad '{path:s}' konnte nicht gelöscht werden",
"backup_deleted": "Datensicherung wurde entfernt",
"backup_deleted": "Backup wurde entfernt",
"backup_extracting_archive": "Entpacke Sicherungsarchiv...",
"backup_hook_unknown": "Datensicherungshook '{hook:s}' unbekannt",
"backup_invalid_archive": "Ungültige Datensicherung",
"backup_nothings_done": "Es gibt keine Änderungen zur Speicherung",
"backup_output_directory_forbidden": "Verbotenes Ausgabeverzeichnis. Datensicherung können nicht in /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var oder in Unterordnern von /home/yunohost.backup/archives erstellt werden",
"backup_output_directory_not_empty": "Ausgabeordner ist nicht leer",
"backup_hook_unknown": "Der Datensicherungshook '{hook:s}' unbekannt",
"backup_invalid_archive": "Dies ist kein Backup-Archiv",
"backup_nothings_done": "Keine Änderungen zur Speicherung",
"backup_output_directory_forbidden": "Wähle ein anderes Ausgabeverzeichnis. Datensicherung können nicht in /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var oder in Unterordnern von /home/yunohost.backup/archives erstellt werden",
"backup_output_directory_not_empty": "Der gewählte Ausgabeordner sollte leer sein",
"backup_output_directory_required": "Für die Datensicherung muss ein Zielverzeichnis angegeben werden",
"backup_running_app_script": "Datensicherung für App '{app:s}' wurd durchgeführt...",
"backup_running_hooks": "Datensicherunghook wird ausgeführt...",
"backup_running_hooks": "Datensicherunghook wird ausgeführt",
"custom_app_url_required": "Es muss eine URL angegeben werden, um deine benutzerdefinierte App {app:s} zu aktualisieren",
"custom_appslist_name_required": "Du musst einen Namen für deine benutzerdefinierte Appliste angeben",
"dnsmasq_isnt_installed": "dnsmasq scheint nicht installiert zu sein. Bitte führe 'apt-get remove bind9 && apt-get install dnsmasq' aus",
@ -71,7 +71,7 @@
"domain_zone_exists": "DNS Zonen Datei existiert bereits",
"domain_zone_not_found": "DNS Zonen Datei kann nicht für Domäne {:s} gefunden werden",
"done": "Erledigt",
"downloading": "Wird heruntergeladen...",
"downloading": "Wird heruntergeladen",
"dyndns_cron_installed": "DynDNS Cronjob erfolgreich angelegt",
"dyndns_cron_remove_failed": "Der DynDNS Cronjob konnte nicht entfernt werden",
"dyndns_cron_removed": "Der DynDNS Cronjob wurde gelöscht",
@ -81,9 +81,9 @@
"dyndns_registered": "Deine DynDNS Domain wurde registriert",
"dyndns_registration_failed": "DynDNS Domain konnte nicht registriert werden: {error:s}",
"dyndns_unavailable": "DynDNS Subdomain ist nicht verfügbar",
"executing_command": "Führe den Behfehl '{command:s}' aus...",
"executing_script": "Skript '{script:s}' wird ausgeührt...",
"extracting": "Wird entpackt...",
"executing_command": "Führe den Behfehl '{command:s}' aus",
"executing_script": "Skript '{script:s}' wird ausgeührt",
"extracting": "Wird entpackt",
"field_invalid": "Feld '{:s}' ist unbekannt",
"firewall_reload_failed": "Die Firewall konnte nicht neu geladen werden",
"firewall_reloaded": "Die Firewall wurde neu geladen",
@ -156,7 +156,7 @@
"restore_hook_unavailable": "Das Wiederherstellungsskript für '{part:s}' steht weder in deinem System noch im Archiv zur Verfügung",
"restore_nothings_done": "Es wurde nicht wiederhergestellt",
"restore_running_app_script": "Wiederherstellung wird ausfeührt für App '{app:s}'...",
"restore_running_hooks": "Wiederherstellung wird gestartet...",
"restore_running_hooks": "Wiederherstellung wird gestartet",
"service_add_configuration": "Füge Konfigurationsdatei {file:s} hinzu",
"service_add_failed": "Der Dienst '{service:s}' kann nicht hinzugefügt werden",
"service_added": "Der Service '{service:s}' wurde erfolgreich hinzugefügt",
@ -189,9 +189,9 @@
"unlimit": "Kein Kontingent",
"unrestore_app": "App '{app:s}' kann nicht Wiederhergestellt werden",
"update_cache_failed": "Konnte APT cache nicht aktualisieren",
"updating_apt_cache": "Die Liste der verfügbaren Pakete wird aktualisiert...",
"updating_apt_cache": "Die Liste der verfügbaren Pakete wird aktualisiert",
"upgrade_complete": "Upgrade vollständig",
"upgrading_packages": "Pakete werden aktualisiert...",
"upgrading_packages": "Pakete werden aktualisiert",
"upnp_dev_not_found": "Es konnten keine UPnP Geräte gefunden werden",
"upnp_disabled": "UPnP wurde deaktiviert",
"upnp_enabled": "UPnP wurde aktiviert",
@ -208,12 +208,12 @@
"yunohost_already_installed": "YunoHost ist bereits installiert",
"yunohost_ca_creation_failed": "Zertifikatsstelle konnte nicht erstellt werden",
"yunohost_configured": "YunoHost wurde konfiguriert",
"yunohost_installing": "YunoHost wird installiert...",
"yunohost_installing": "YunoHost wird installiert",
"yunohost_not_installed": "YunoHost ist nicht oder unvollständig installiert worden. Bitte 'yunohost tools postinstall' ausführen",
"app_not_properly_removed": "{app:s} wurde nicht ordnungsgemäß entfernt",
"service_regenconf_failed": "Konnte die Konfiguration für folgende Dienste nicht neu erzeugen: {services}",
"not_enough_disk_space": "Zu wenig freier Speicherplatz unter '{path:s}' verfügbar",
"backup_creation_failed": "Erstellen des Backups fehlgeschlagen",
"backup_creation_failed": "Konnte Backup-Archiv nicht erstellen",
"service_conf_up_to_date": "Die Konfiguration für den Dienst '{service}' ist bereits aktuell",
"package_not_installed": "Das Paket '{pkgname}' ist nicht installiert",
"pattern_positive_number": "Muss eine positive Zahl sein",
@ -221,7 +221,7 @@
"package_unexpected_error": "Ein unerwarteter Fehler trat bei der Verarbeitung des Pakets '{pkgname}' auf",
"app_incompatible": "Die Anwendung {app} ist nicht mit deiner YunoHost-Version kompatibel",
"app_not_correctly_installed": "{app:s} 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_failed": "Anforderungen für {app} werden nicht erfüllt: {error}",
"app_requirements_unmeet": "Anforderungen für {app} werden nicht erfüllt, das Paket {pkgname} ({version}) muss {spec} sein",
"app_unsupported_remote_type": "Für die App wurde ein nicht unterstützer Steuerungstyp verwendet",
@ -277,30 +277,30 @@
"service_regenconf_pending_applying": "Überprüfe ausstehende Konfigurationen, die für den Server '{service}' notwendig sind...",
"certmanager_http_check_timeout": "Eine Zeitüberschreitung ist aufgetreten als der Server versuchte sich selbst über HTTP mit der öffentlichen IP (Domain {domain:s} mit der IP {ip:s}) zu erreichen. Möglicherweise ist dafür hairpinning oder eine falsch konfigurierte Firewall/Router deines Servers dafür verantwortlich.",
"certmanager_couldnt_fetch_intermediate_cert": "Eine Zeitüberschreitung ist aufgetreten als der Server versuchte die Teilzertifikate von Let's Encrypt zusammenzusetzen. Die Installation/Erneuerung des Zertifikats wurde abgebrochen - bitte versuche es später erneut.",
"appslist_retrieve_bad_format": "Die empfangene Datei der Appliste {appslist:s} ist ungültig",
"appslist_retrieve_bad_format": "Die geladene Appliste {appslist:s} ist ungültig",
"domain_hostname_failed": "Erstellen des neuen Hostnamens fehlgeschlagen",
"appslist_name_already_tracked": "Es gibt bereits eine registrierte App-Liste mit Namen {name:s}.",
"appslist_url_already_tracked": "Es gibt bereits eine registrierte Anwendungsliste mit dem URL {url:s}.",
"appslist_migrating": "Migriere Anwendungsliste {appslist:s} ...",
"appslist_could_not_migrate": "Konnte Anwendungsliste {appslist:s} nicht migrieren. Konnte die URL nicht verarbeiten... Der alte Cron-Job wurde unter {bkp_file:s} beibehalten.",
"appslist_corrupted_json": "Konnte die Anwendungslisten. Es scheint, dass {filename:s} beschädigt ist.",
"appslist_url_already_tracked": "Es gibt bereits eine registrierte Anwendungsliste mit der URL {url:s}.",
"appslist_migrating": "Migriere Anwendungsliste {appslist:s} ",
"appslist_could_not_migrate": "Konnte die Anwendungsliste {appslist:s} nicht migrieren. Konnte die URL nicht verarbeiten... Der alte Cron-Job wurde unter {bkp_file:s} beibehalten.",
"appslist_corrupted_json": "Anwendungslisten konnte nicht geladen werden. Es scheint, dass {filename:s} beschädigt ist.",
"yunohost_ca_creation_success": "Die lokale Zertifizierungs-Authorität wurde angelegt.",
"app_already_installed_cant_change_url": "Diese Application ist bereits installiert. Die URL kann durch diese Funktion nicht modifiziert werden. Überprüfe ob `app changeurl` verfügbar ist.",
"app_change_no_change_url_script": "Die Application {app_name:s} unterstützt das anpassen der URL noch nicht. Sie muss gegebenenfalls erweitert werden.",
"app_change_url_failed_nginx_reload": "NGINX konnte nicht neu gestartet werden. Hier ist der Output von 'nginx -t':\n{nginx_errors:s}",
"app_change_url_identical_domains": "Die alte und neue domain/url_path sind identisch: ('{domain:s} {path:s}'). Es gibt nichts zu tun.",
"app_already_up_to_date": "{app:s} ist schon aktuell",
"app_already_up_to_date": "{app:s} ist bereits aktuell",
"backup_abstract_method": "Diese Backup-Methode wird noch nicht unterstützt",
"backup_applying_method_tar": "Erstellen des Backup-tar Archives...",
"backup_applying_method_copy": "Kopiere alle Dateien ins Backup...",
"app_change_url_no_script": "Die Anwendung '{app_name:s}' unterstützt bisher keine URL-Modufikation. Vielleicht gibt es eine Aktualisierung der Anwendung.",
"backup_applying_method_tar": "Erstellen des Backup-tar Archives",
"backup_applying_method_copy": "Kopiere alle Dateien ins Backup",
"app_change_url_no_script": "Die Anwendung '{app_name:s}' unterstützt bisher keine URL-Modufikation. Vielleicht gibt es eine Aktualisierung.",
"app_location_unavailable": "Diese URL ist nicht verfügbar oder wird von einer installierten Anwendung genutzt:\n{apps:s}",
"backup_applying_method_custom": "Rufe die benutzerdefinierte Backup-Methode '{method:s}' auf...",
"backup_applying_method_custom": "Rufe die benutzerdefinierte Backup-Methode '{method:s}' auf",
"backup_archive_system_part_not_available": "Der System-Teil '{part:s}' ist in diesem Backup nicht enthalten",
"backup_archive_mount_failed": "Das Einbinden des Backup-Archives ist fehlgeschlagen",
"backup_archive_writing_error": "Die Dateien konnten nicht in der komprimierte Archiv-Backup hinzugefügt werden",
"app_change_url_success": "Erfolgreiche Änderung der URL von {app:s} zu {domain:s}{path:s}",
"backup_applying_method_borg": "Sende alle Dateien zur Sicherung ins borg-backup repository...",
"backup_archive_writing_error": "Die Dateien '{source:s} (im Ordner '{dest:s}') konnten nicht in das komprimierte Archiv-Backup '{archive:s}' hinzugefügt werden",
"app_change_url_success": "{app:s} URL ist nun {domain:s}{path:s}",
"backup_applying_method_borg": "Sende alle Dateien zur Sicherung ins borg-backup repository",
"invalid_url_format": "ungültiges URL Format",
"global_settings_bad_type_for_setting": "Falscher Typ für Einstellung {setting: s}. Empfangen: {receive_type: s}, aber erwartet: {expected_type: s}",
"global_settings_bad_choice_for_enum": "Falsche Wahl für die Einstellung {setting: s}. Habe '{choice: s}' erhalten, aber es stehen nur folgende Auswahlmöglichkeiten zur Verfügung: {available_choices: s}",
@ -325,34 +325,94 @@
"backup_permission": "Sicherungsberechtigung für App {app: s}",
"backup_output_symlink_dir_broken": "Sie haben einen fehlerhaften Symlink anstelle Ihres Archivverzeichnisses '{path: s}'. Möglicherweise haben Sie ein spezielles Setup, um Ihre Daten auf einem anderen Dateisystem zu sichern. In diesem Fall haben Sie wahrscheinlich vergessen, Ihre Festplatte oder Ihren USB-Schlüssel erneut einzuhängen oder anzuschließen.",
"backup_mount_archive_for_restore": "Archiv für Wiederherstellung vorbereiten…",
"backup_method_tar_finished": "Sicherungs-Tar-Archiv erstellt",
"backup_method_tar_finished": "Tar-Backup-Archiv erstellt",
"backup_method_custom_finished": "Benutzerdefinierte Sicherungsmethode '{method: s}' beendet",
"backup_method_copy_finished": "Sicherungskopie beendet",
"backup_method_borg_finished": "Backup in Borg beendet",
"backup_custom_need_mount_error": "Bei der benutzerdefinierten Sicherungsmethode ist beim Arbeitsschritt \"Braucht ein Einhängen/Verbinden\" (need_mount) ein Fehler aufgetreten",
"backup_custom_mount_error": "Bei der benutzerdefinierten Sicherungsmethode ist beim Arbeitsschritt \"Einhängen/Verbinden\" ein Fehler aufgetreten",
"backup_custom_backup_error": "Bei der benutzerdefinierten Sicherungsmethode ist beim Arbeitsschritt \"Sicherung\" ein Fehler aufgetreten",
"backup_csv_creation_failed": "Die CSV-Datei, die für zukünftige Wiederherstellungsvorgänge erforderlich ist, kann nicht erstellt werden",
"backup_csv_creation_failed": "Die zur Wiederherstellung erforderliche CSV-Datei kann nicht erstellt werden",
"backup_couldnt_bind": "{Src: s} konnte nicht an {dest: s} angebunden werden.",
"backup_borg_not_implemented": "Die Borg-Sicherungsmethode ist noch nicht implementiert",
"backup_ask_for_copying_if_needed": "Einige Dateien konnten mit der Methode, die es vermeidet vorübergehend Speicherplatz auf dem System zu verschwenden, nicht gesichert werden. Zur Durchführung der Sicherung sollten vorübergehend {size: s} MB verwendet werden. Sind Sie einverstanden?",
"backup_actually_backuping": "Erstelle nun ein Backup-Archiv aus den gesammelten Dateien …",
"backup_actually_backuping": "Erstellt ein Backup-Archiv aus den gesammelten Dateien …",
"ask_path": "Pfad",
"ask_new_path": "Neuer Pfad",
"ask_new_domain": "Neue Domain",
"apps_permission_restoration_failed": "Die Berechtigung '{permission: s}' für die Wiederherstellung der App {app: s} ist fehlgeschlagen",
"apps_permission_restoration_failed": "Erteilen der Berechtigung '{permission: s}' für die Wiederherstellung der App {app: s} erforderlich",
"apps_permission_not_found": "Keine Berechtigung für die installierten Apps gefunden",
"app_upgrade_some_app_failed": "Einige Anwendungen können nicht aktualisiert werden",
"app_upgrade_app_name": "App {App} wird jetzt aktualisiert…",
"app_upgrade_app_name": "{App} wird jetzt aktualisiert…",
"app_upgrade_several_apps": "Die folgenden Apps werden aktualisiert: {apps}",
"app_start_restore": "Anwendung {app} wird wiederhergestellt…",
"app_start_backup": "Sammeln von Dateien, die für {app} gesichert werden sollen…",
"app_start_remove": "Anwendung {app} wird entfernt…",
"app_start_install": "Anwendung {app} wird installiert…",
"app_not_upgraded": "Die folgenden Apps wurden nicht aktualisiert: {apps}",
"app_not_upgraded": "Die App '{failed_app}' konnte nicht aktualisiert werden. Infolgedessen wurden die folgenden App-Upgrades abgebrochen: {apps}",
"app_make_default_location_already_used": "Die App \"{app}\" kann nicht als Standard für die Domain \"{domain}\" festgelegt werden. Sie wird bereits von der anderen App \"{other_app}\" verwendet",
"aborting": "Breche ab.",
"app_action_cannot_be_ran_because_required_services_down": "Diese App erfordert einige Dienste, die derzeit nicht verfügbar sind. Bevor Sie fortfahren, sollten Sie versuchen, die folgenden Dienste neu zu starten (und möglicherweise untersuchen, warum sie nicht verfügbar sind): {services}",
"already_up_to_date": "Nichts zu tun! Alles ist bereits auf dem neusten Stand!",
"admin_password_too_long": "Bitte ein Passwort kürzer als 127 Zeichen wählen."
"already_up_to_date": "Nichts zu tun. Alles ist bereits auf dem neusten Stand.",
"admin_password_too_long": "Bitte ein Passwort kürzer als 127 Zeichen wählen",
"app_action_broke_system": "Diese Aktion hat anscheinend diese wichtigen Services gestört: {services}",
"apps_already_up_to_date": "Alle Apps sind bereits aktuell",
"backup_copying_to_organize_the_archive": "Kopieren von {size: s} MB, um das Archiv zu organisieren",
"app_upgrade_stopped": "Das Upgrade aller Anwendungen wurde gestoppt, um mögliche Schäden zu vermeiden, da das Upgrade der vorherigen Anwendung fehlgeschlagen ist",
"group_already_disallowed": "Die Gruppe '{group:s}' hat bereits die Berechtigungen '{permission:s}' für die App '{app:s}' deaktiviert",
"global_settings_setting_security_ssh_compatibility": "Kompatibilität vs. Sicherheitskompromiss für den SSH-Server. Beeinflusst die Chiffren (und andere sicherheitsrelevante Aspekte)",
"group_deleted": "Gruppe '{group}' gelöscht",
"group_deletion_failed": "Kann Gruppe '{group}' nicht löschen",
"group_deletion_not_allowed": "Die Gruppe {group:s} kann nicht manuell gelöscht werden.",
"dyndns_provider_unreachable": "Dyndns-Anbieter {provider} kann nicht erreicht werden: Entweder ist dein YunoHost nicht korrekt mit dem Internet verbunden oder der Dynette-Server ist ausgefallen.",
"group_already_allowed": "Gruppe '{group:s}' hat bereits die Berechtigung '{permission:s}' für die App '{app:s}' eingeschaltet",
"group_name_already_exist": "Gruppe {name:s} existiert bereits",
"group_created": "Gruppe '{group}' angelegt",
"group_creation_failed": "Kann Gruppe '{group}' nicht anlegen",
"group_unknown": "Die Gruppe '{group:s}' ist unbekannt",
"group_updated": "Gruppe '{group:s}' erneuert",
"group_update_failed": "Kann Gruppe '{group:s}' nicht anpassen",
"log_does_exists": "Es gibt kein Operationsprotokoll mit dem Namen'{log}', verwende'yunohost log list', um alle verfügbaren Operationsprotokolle anzuzeigen",
"log_app_removelist": "Entferne eine Applikationsliste",
"log_operation_unit_unclosed_properly": "Die Operationseinheit wurde nicht richtig geschlossen",
"log_app_removeaccess": "Entziehe Zugriff auf '{}'",
"global_settings_setting_security_postfix_compatibility": "Kompatibilität vs. Sicherheitskompromiss für den Postfix-Server. Beeinflusst die Chiffren (und andere sicherheitsrelevante Aspekte)",
"log_category_404": "Die Log-Kategorie '{category}' existiert nicht",
"global_settings_unknown_type": "Unerwartete Situation, die Einstellung {setting:s} scheint den Typ {unknown_type:s} 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 dpkg --configure -a` ausführst.",
"global_settings_unknown_setting_from_settings_file": "Unbekannter Schlüssel in den Einstellungen: '{setting_key:s}', 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>'",
"global_settings_setting_example_bool": "Beispiel einer booleschen Option",
"log_app_fetchlist": "Füge eine Applikationsliste hinzu",
"log_help_to_get_log": "Um das Protokoll der Operation '{desc}' anzuzeigen, verwende den Befehl 'yunohost log display {name}'",
"global_settings_setting_security_nginx_compatibility": "Kompatibilität vs. Sicherheitskompromiss für den Webserver NGINX. Beeinflusst die Chiffren (und andere sicherheitsrelevante Aspekte)",
"backup_php5_to_php7_migration_may_fail": "Dein Archiv konnte nicht für PHP 7 konvertiert werden, Du kannst deine PHP-Anwendungen möglicherweise nicht wiederherstellen (Grund: {error:s})",
"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_example_string": "Beispiel einer string Option",
"log_app_addaccess": "Füge Zugriff auf '{}' hinzu",
"log_app_remove": "Entferne die Anwendung '{}'",
"global_settings_setting_example_int": "Beispiel einer int Option",
"global_settings_cant_open_settings": "Einstellungsdatei konnte nicht geöffnet werden, Grund: {reason:s}",
"global_settings_cant_write_settings": "Einstellungsdatei konnte nicht gespeichert werden, Grund: {reason:s}",
"log_app_install": "Installiere die Anwendung '{}'",
"global_settings_reset_success": "Frühere Einstellungen werden nun auf {path:s} gesichert",
"log_app_upgrade": "Upgrade der Anwendung '{}'",
"good_practices_about_admin_password": "Sie sind nun dabei, ein neues Administrationspasswort zu definieren. Das Passwort sollte mindestens 8 Zeichen lang sein - obwohl es sinnvoll ist, ein längeres Passwort (z.B. eine Passphrase) und/oder eine Variation von Zeichen (Groß- und Kleinschreibung, Ziffern und Sonderzeichen) zu verwenden.",
"log_corrupted_md_file": "Die mit Protokollen verknüpfte YAML-Metadatendatei ist beschädigt: '{md_file}\nFehler: {error}''",
"global_settings_cant_serialize_settings": "Einstellungsdaten konnten nicht serialisiert werden, Grund: {reason:s}",
"log_help_to_get_failed_log": "Der Vorgang'{desc}' konnte nicht abgeschlossen werden. Bitte teile das vollständige Protokoll dieser Operation mit dem Befehl 'yunohost log display {name} --share', um Hilfe zu erhalten",
"backup_no_uncompress_archive_dir": "Dieses unkomprimierte Archivverzeichnis gibt es nicht",
"log_app_change_url": "Ändere die URL der Anwendung '{}'",
"global_settings_setting_security_password_user_strength": "Stärke des Benutzerpassworts",
"good_practices_about_user_password": "Du bist nun dabei, ein neues Benutzerpasswort zu definieren. Das Passwort sollte mindestens 8 Zeichen lang sein - obwohl es ratsam ist, ein längeres Passwort (z.B. eine Passphrase) und/oder eine Variation von Zeichen (Groß- und Kleinschreibung, Ziffern und Sonderzeichen) zu verwenden.",
"global_settings_setting_example_enum": "Beispiel einer enum Option",
"log_link_to_failed_log": "Der Vorgang konnte nicht abgeschlossen werden '{desc}'. Bitte gib das vollständige Protokoll dieser Operation mit <a href=\"#/tools/logs/{name}\">Klicken Sie hier</a> an, um Hilfe zu erhalten",
"backup_cant_mount_uncompress_archive": "Das unkomprimierte Archiv konnte nicht als schreibgeschützt gemountet werden",
"backup_csv_addition_failed": "Es konnten keine Dateien zur Sicherung in die CSV-Datei hinzugefügt werden",
"log_app_clearaccess": "Entziehe alle Zugriffe auf '{}'",
"global_settings_setting_security_password_admin_strength": "Stärke des Admin-Passworts",
"global_settings_key_doesnt_exists": "Der Schlüssel'{settings_key:s}' existiert nicht in den globalen Einstellungen, du kannst alle verfügbaren Schlüssel sehen, indem du 'yunohost settings list' ausführst",
"log_app_makedefault": "Mache '{}' zur Standard-Anwendung",
"hook_json_return_error": "Konnte die Rückkehr vom Einsprungpunkt {path:s} nicht lesen. Fehler: {msg:s}. Unformatierter Inhalt: {raw_content}",
"app_full_domain_unavailable": "Es tut uns leid, aber diese Anwendung erfordert die Installation einer vollständigen Domäne, aber einige andere Anwendungen sind bereits auf der Domäne'{domain}' installiert. Eine mögliche Lösung ist das Hinzufügen und Verwenden einer Subdomain, die dieser Anwendung zugeordnet ist."
}

View file

@ -6,7 +6,7 @@
"admin_password_changed": "The administration password got changed",
"admin_password_too_long": "Please choose a password shorter than 127 characters",
"already_up_to_date": "Nothing to do. Everything is already up-to-date.",
"app_action_cannot_be_ran_because_required_services_down": "This app requires some services which are currently down. Before continuing, you should try to restart the following services (and possibly investigate why they are down): {services}",
"app_action_cannot_be_ran_because_required_services_down": "These required services should be running to run this action: {services}. Try restarting them to continue (and possibly investigate why they are down).",
"app_action_broke_system": "This action seem to have broke these important services: {services}",
"app_already_installed": "{app:s} is already installed",
"app_already_installed_cant_change_url": "This app is already installed. The URL cannot be changed just by this function. Look into `app changeurl` if it's available.",
@ -14,54 +14,56 @@
"app_argument_choice_invalid": "Use one of these choices '{choices:s}' for the argument '{name:s}'",
"app_argument_invalid": "Pick a valid value for the argument '{name:s}': {error:s}",
"app_argument_required": "Argument '{name:s}' is required",
"app_change_no_change_url_script": "The application {app_name:s} doesn't support changing its URL yet, you might need to upgrade it.",
"app_change_url_failed_nginx_reload": "Could not reload NGINX. Here is the output of 'nginx -t':\n{nginx_errors:s}",
"app_change_url_identical_domains": "The old and new domain/url_path are identical ('{domain:s}{path:s}'), nothing to do.",
"app_change_url_no_script": "This application '{app_name:s}' doesn't support URL modification yet. Maybe you should upgrade it.",
"app_change_url_no_script": "The app '{app_name:s}' doesn't support URL modification yet. Maybe you should upgrade it.",
"app_change_url_success": "{app:s} URL is now {domain:s}{path:s}",
"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_id_invalid": "Invalid app ID",
"app_install_files_invalid": "These files cannot be installed",
"app_install_failed": "Could not install {app}: {error}",
"app_install_script_failed": "An error occurred inside the app installation script",
"app_location_already_used": "The app '{app}' is already installed in ({path})",
"app_make_default_location_already_used": "Can't make the app '{app}' the default on the domain, {domain} is already in use by the other app '{other_app}'",
"app_make_default_location_already_used": "Can't make the app '{app}' the default on the domain, '{domain}' is already in use by the other app '{other_app}'",
"app_location_install_failed": "Cannot install the app there because it conflicts with the app '{other_app}' already installed in '{other_path}'",
"app_location_unavailable": "This URL is either unavailable, or conflicts with the already installed app(s):\n{apps:s}",
"app_manifest_invalid": "Something is wrong with the app manifest: {error}",
"app_no_upgrade": "All applications are already up-to-date",
"app_not_upgraded": "The app '{failed_app}' failed to upgrade, and as a consequence the following apps upgrades have been cancelled: {apps}",
"app_upgrade_stopped": "The upgrade of all applications has been stopped to prevent possible damage because the previous application failed to upgrade",
"app_upgrade_stopped": "Upgrading all apps was stopped to prevent possible damage because one app could not be upgraded",
"app_not_correctly_installed": "{app:s} seems to be incorrectly installed",
"app_not_installed": "Could not find the application '{app:s}' in the list of installed apps: {all_apps}",
"app_not_installed": "Could not find the app '{app:s}' in the list of installed apps: {all_apps}",
"app_not_properly_removed": "{app:s} has not been properly removed",
"app_package_need_update": "The app {app} package needs to be updated to follow YunoHost changes",
"app_removed": "{app:s} removed",
"app_requirements_checking": "Checking required packages for {app}…",
"app_requirements_failed": "Some requirements are not met for {app}: {error}",
"app_requirements_unmeet": "Requirements are not met for {app}, the package {pkgname} ({version}) must be {spec}",
"app_remove_after_failed_install": "Removing the app following the installation failure…",
"app_sources_fetch_failed": "Could not fetch sources files, is the URL correct?",
"app_start_install": "Installing application {app}…",
"app_start_remove": "Removing application {app}…",
"app_start_backup": "Collecting files to be backed up for {app}…",
"app_start_restore": "Restoring application {app}…",
"app_start_install": "Installing the app '{app}'…",
"app_start_remove": "Removing the app '{app}'…",
"app_start_backup": "Collecting files to be backed up for the app '{app}'…",
"app_start_restore": "Restoring the app '{app}'…",
"app_unknown": "Unknown app",
"app_unsupported_remote_type": "Unsupported remote type used for the app",
"app_upgrade_several_apps": "The following apps will be upgraded: {apps}",
"app_upgrade_app_name": "Now upgrading {app}…",
"app_upgrade_failed": "Could not upgrade {app:s}",
"app_upgrade_some_app_failed": "Some applications could not be upgraded",
"app_upgrade_some_app_failed": "Some apps could not be upgraded",
"app_upgraded": "{app:s} upgraded",
"apps_already_up_to_date": "All apps are already up-to-date",
"apps_permission_not_found": "No permission found for the installed apps",
"apps_permission_restoration_failed": "Grant the permission permission '{permission:s}' to restore {app:s}",
"appslist_corrupted_json": "Could not load the application lists. It looks like {filename:s} is damaged.",
"appslist_could_not_migrate": "Could not migrate the app list {appslist:s}! Could not parse the URL… The old cron job was kept kept in {bkp_file:s}.",
"appslist_fetched": "Updated application list {appslist:s} fetched",
"appslist_migrating": "Migrating application list {appslist:s}…",
"appslist_name_already_tracked": "A registered application list with name {name:s} already exists.",
"appslist_removed": "{appslist:s} application list removed",
"appslist_retrieve_bad_format": "Could not read the fetched application list {appslist:s}",
"appslist_retrieve_error": "Cannot retrieve the remote application list {appslist:s}: {error:s}",
"appslist_unknown": "Application list {appslist:s} unknown.",
"appslist_url_already_tracked": "There is already a registered application list with the URL {url:s}.",
"appslist_corrupted_json": "Could not load the app lists. It looks like {filename:s} is damaged.",
"appslist_could_not_migrate": "Could not migrate the app list '{appslist:s}'! Could not parse the URL… The old cron job was kept kept in {bkp_file:s}.",
"appslist_fetched": "Updated the app list '{appslist:s}'",
"appslist_migrating": "Migrating the app list '{appslist:s}'…",
"appslist_name_already_tracked": "A registered app list with the name {name:s} already exists.",
"appslist_removed": "The '{appslist:s}' app list was removed",
"appslist_retrieve_bad_format": "Could not read the fetched app list '{appslist:s}'",
"appslist_retrieve_error": "Cannot retrieve the remote app list '{appslist:s}': {error:s}",
"appslist_unknown": "The app list '{appslist:s}' is unknown.",
"appslist_url_already_tracked": "There is already a registered app list with the URL {url:s}.",
"ask_current_admin_password": "Current administration password",
"ask_email": "E-mail address",
"ask_firstname": "First name",
@ -74,7 +76,6 @@
"ask_password": "Password",
"ask_path": "Path",
"backup_abstract_method": "This backup method has yet to be implemented",
"backup_action_required": "You must specify something to save",
"backup_actually_backuping": "Creating a backup archive from the collected files…",
"backup_app_failed": "Could not back up the app '{app:s}'",
"backup_applying_method_borg": "Sending all files to backup into borg-backup repository…",
@ -83,29 +84,25 @@
"backup_applying_method_tar": "Creating the backup TAR archive…",
"backup_archive_app_not_found": "Could not find the app '{app:s}' in the backup archive",
"backup_archive_broken_link": "Could not access the backup archive (broken link to {path:s})",
"backup_archive_mount_failed": "Could not mount the backup archive",
"backup_archive_name_exists": "A backup archive with this name already exists.",
"backup_archive_name_unknown": "Unknown local backup archive named '{name:s}'",
"backup_archive_open_failed": "Could not open the backup archive",
"backup_archive_system_part_not_available": "System part '{part:s}' unavailable in this backup",
"backup_archive_writing_error": "Could not add the files '{source:s}' (named in the archive '{dest:s}') to be backed up into the compressed archive '{archive:s}'",
"backup_ask_for_copying_if_needed": "Some files could not be prepared for backup using the method that avoids temporarily wasting space on the system. To perform the backup, {size:s}MB will be temporarily. Do you agree?",
"backup_ask_for_copying_if_needed": "Do you want to perform the backup using {size:s} MB temporarily? (This way is used since some files could not be prepared using a more efficient method.)",
"backup_borg_not_implemented": "The Borg backup method is not yet implemented",
"backup_cant_mount_uncompress_archive": "Could not mount the uncompressed archive as write protected",
"backup_cleaning_failed": "Could not clean-up the temporary backup folder",
"backup_copying_to_organize_the_archive": "Copying {size:s}MB to organize the archive",
"backup_couldnt_bind": "Could not bind {src:s} to {dest:s}.",
"backup_created": "Backup created",
"backup_creating_archive": "Creating the backup archive…",
"backup_creation_failed": "Could not create the backup archive",
"backup_csv_addition_failed": "Could not add files to backup into the CSV file",
"backup_csv_creation_failed": "Could not create the CSV file needed for restoration",
"backup_custom_backup_error": "Custom backup method could not get past the 'backup' step",
"backup_custom_mount_error": "Custom backup method could not get past the 'mount' step",
"backup_custom_need_mount_error": "Custom backup method could not get past 'need_mount' step",
"backup_delete_error": "Could not delete '{path:s}'",
"backup_deleted": "Backup deleted",
"backup_extracting_archive": "Extracting backup archive…",
"backup_hook_unknown": "The backup hook '{hook:s}' is unknown",
"backup_invalid_archive": "This is not a backup archive",
"backup_method_borg_finished": "Backup into Borg finished",
@ -118,7 +115,7 @@
"backup_output_directory_forbidden": "Pick a different output directory. Backups can not be created in /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var or /home/yunohost.backup/archives sub-folders",
"backup_output_directory_not_empty": "You should pick an empty output directory",
"backup_output_directory_required": "You must provide an output directory for the backup",
"backup_output_symlink_dir_broken": "You have a broken symlink in place of your archive directory '{path:s}'. You may have a specific setup to backup your data on another filesystem, in this case you probably forgot to remount or plug in your hard-drive or USB key.",
"backup_output_symlink_dir_broken": "Your archive directory '{path:s}' is a broken symlink. Maybe you forgot to re/mount or plug in the storage medium it points to.",
"backup_permission": "Backup permission for app {app:s}",
"backup_php5_to_php7_migration_may_fail": "Could not convert your archive to support PHP 7, you may be unable to restore your PHP apps (reason: {error:s})",
"backup_running_hooks": "Running backup hooks…",
@ -141,7 +138,6 @@
"certmanager_domain_cert_not_selfsigned": "The certificate for domain {domain:s} is not self-signed. Are you sure you want to replace it? (Use '--force' to do so.)",
"certmanager_domain_dns_ip_differs_from_public_ip": "The DNS 'A' record for the domain '{domain:s}' is different from this server IP. If you recently modified your A record, please wait for it to propagate (some DNS propagation checkers are available online). (If you know what you are doing, use '--no-checks' to turn off those checks.)",
"certmanager_domain_http_not_working": "It seems the domain {domain:s} cannot be accessed through HTTP. Check that your DNS and NGINX configuration is correct",
"certmanager_domain_not_resolved_locally": "The domain {domain:s} cannot be resolved from inside your YunoHost server. This might happen if you recently modified your DNS record. If so, please wait a few hours for it to propagate. If the issue persists, consider adding {domain:s} to /etc/hosts. (If you know what you are doing, use '--no-checks' to turn off those checks.)",
"certmanager_domain_unknown": "Unknown domain '{domain:s}'",
"certmanager_error_no_A_record": "No DNS 'A' record found for '{domain:s}'. You need to make your domain name point to your machine to be able to install a Let's Encrypt certificate. (If you know what you are doing, use '--no-checks' to turn off those checks.)",
"certmanager_hit_rate_limit": "Too many certificates already issued for this exact set of domains {domain:s} recently. Please try again later. See https://letsencrypt.org/docs/rate-limits/ for more details",
@ -149,37 +145,31 @@
"certmanager_no_cert_file": "Could not read the certificate file for the domain {domain:s} (file: {file:s})",
"certmanager_self_ca_conf_file_not_found": "Could not find configuration file for self-signing authority (file: {file:s})",
"certmanager_unable_to_parse_self_CA_name": "Could not parse name of self-signing authority (file: {file:s})",
"confirm_app_install_warning": "Warning: This application 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:s}] ",
"confirm_app_install_danger": "WARNING! This application is still experimental (if not explicitly not working) and it is likely to break your system! You should probably NOT install it unless you know what you are doing. Are you willing to take that risk? [{answers:s}] ",
"confirm_app_install_thirdparty": "WARNING! Installing third-party applications may compromise the integrity and security of your system. You should probably NOT install it unless you know what you are doing. Are you willing to take that risk? [{answers:s}] ",
"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:s}] ",
"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 break your system… If you are willing to take that risk anyway, type '{answers:s}'",
"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 break your system… If you are willing to take that risk anyway, type '{answers:s}'",
"custom_app_url_required": "You must provide a URL to upgrade your custom app {app:s}",
"custom_appslist_name_required": "You must provide a name for your custom app list",
"diagnosis_debian_version_error": "Could not retrieve the Debian version: {error}",
"diagnosis_kernel_version_error": "Could not retrieve kernel version: {error}",
"diagnosis_monitor_disk_error": "Could not monitor disks: {error}",
"diagnosis_monitor_network_error": "Could not monitor network: {error}",
"diagnosis_monitor_system_error": "Could not monitor system: {error}",
"diagnosis_no_apps": "No installed application",
"diagnosis_no_apps": "No such installed app",
"dpkg_is_broken": "You cannot do this right now because dpkg/APT (the system package managers) seems to be in a broken state… You can try to solve this issue by connecting through SSH and running `sudo dpkg --configure -a`.",
"dpkg_lock_not_available": "This command can't be ran right now because another program seems to be using the lock of dpkg (the system package manager)",
"dnsmasq_isnt_installed": "Dnsmasq does not seem to be installed, please run 'apt-get remove bind9 && apt-get install it'",
"domain_cannot_remove_main": "Cannot remove main domain. Set one first",
"domain_cert_gen_failed": "Could not generate certificate",
"domain_created": "Domain created",
"domain_creation_failed": "Could not create domain",
"domain_creation_failed": "Could not create domain {domain}: {error}",
"domain_deleted": "Domain deleted",
"domain_deletion_failed": "Could not delete domain",
"domain_deletion_failed": "Could not delete domain {domain}: {error}",
"domain_dns_conf_is_just_a_recommendation": "This command shows you the *recommended* configuration. It does not actually set up the DNS configuration for you. It is your responsability to configure your DNS zone in your registrar according to this recommendation.",
"domain_dyndns_already_subscribed": "You have already subscribed to a DynDNS domain",
"domain_dyndns_dynette_is_unreachable": "Could not reach YunoHost dynette, either your YunoHost is not correctly connected to the Internet, or the dynette server is down. Error: {error}",
"domain_dyndns_invalid": "This domain can not be used with DynDNS",
"domain_dyndns_root_unknown": "Unknown DynDNS root domain",
"domain_exists": "The domain already exists",
"domain_hostname_failed": "Could not set new hostname. This might cause an issue later (it might be fine).",
"domain_uninstall_app_first": "One or more apps are installed on this domain. Please uninstall them before proceeding to domain removal",
"domain_unknown": "Unknown domain",
"domain_zone_exists": "DNS zone file already exists",
"domain_zone_not_found": "DNS zone file not found for domain {:s}",
"domains_available": "Available domains:",
"done": "Done",
"downloading": "Downloading…",
@ -193,13 +183,11 @@
"dyndns_key_generating": "Generating DNS key… It may take a while.",
"dyndns_key_not_found": "DNS key not found for the domain",
"dyndns_no_domain_registered": "No domain registered with DynDNS",
"dyndns_provider_unreachable": "Unable to reach Dyndns provider {provider}: either your YunoHost is not correctly connected to the internet or the dynette server is down.",
"dyndns_registered": "DynDNS domain registered",
"dyndns_registration_failed": "Could not register DynDNS domain: {error:s}",
"dyndns_domain_not_provided": "DynDNS provider {provider:s} cannot provide domain {domain:s}.",
"dyndns_unavailable": "The domain '{domain:s}' is unavailable.",
"edit_group_not_allowed": "You are not allowed to edit the group {group:s}",
"edit_permission_with_group_all_users_not_allowed": "You are not allowed to edit permission for the group 'all_users', use 'yunohost user permission clear APP' or 'yunohost user permission add APP -u USER' instead.",
"error_when_removing_sftpuser_group": "Could not remove the sftpusers group",
"executing_command": "Executing command '{command:s}'…",
"executing_script": "Executing script '{script:s}'…",
"extracting": "Extracting…",
@ -209,7 +197,6 @@
"firewall_reload_failed": "Could not reload the firewall",
"firewall_reloaded": "Firewall reloaded",
"firewall_rules_cmd_failed": "Some firewall rules commands have failed. More info in log.",
"format_datetime_short": "%m/%d/%Y %I:%M %p",
"global_settings_bad_choice_for_enum": "Bad choice for setting {setting:s}, received '{choice:s}', but available choices are: {available_choices:s}",
"global_settings_bad_type_for_setting": "Bad type for setting {setting:s}, received {received_type:s}, expected {expected_type:s}",
"global_settings_cant_open_settings": "Could not open settings file, reason: {reason:s}",
@ -231,26 +218,29 @@
"global_settings_unknown_type": "Unexpected situation, the setting {setting:s} appears to have the type {unknown_type:s} but it is not a type supported by the system.",
"good_practices_about_admin_password": "You are now about to define a new administration password. The password should be at-least 8 characters—though it is good practice to use a longer password (i.e. a passphrase) and/or to use a variation of characters (uppercase, lowercase, digits and special characters).",
"good_practices_about_user_password": "You are now about to define a new user password. The password should be at least 8 characters—though it is good practice to use longer password (i.e. a passphrase) and/or to a variation of characters (uppercase, lowercase, digits and special characters).",
"group_already_allowed": "Group '{group:s}' already has permission '{permission:s}' turned on for the app '{app:s}'",
"group_already_disallowed": "Group '{group:s}' already has permissions '{permission:s}' turned off for the app '{app:s}'",
"group_name_already_exist": "Group {name:s} already exists",
"group_already_exist": "Group {group} already exists",
"group_already_exist_on_system": "Group {group} already exists in the system groups",
"group_created": "Group '{group}' created",
"group_creation_failed": "Could not create the group '{group}'",
"group_creation_failed": "Could not create the group '{group}': {error}",
"group_cannot_edit_all_users": "The group 'all_users' cannot be edited manually. It is a special group meant to contain all users registered in YunoHost",
"group_cannot_edit_visitors": "The group 'visitors' cannot be edited manually. It is a special group representing anonymous visitors",
"group_cannot_edit_primary_group": "The group '{group}' cannot be edited manually. It is the primary group meant to contain only one specific user.",
"group_cannot_be_edited": "The group {group} cannot be edited manually.",
"group_cannot_be_deleted": "The group {group} cannot be deleted manually.",
"group_deleted": "Group '{group}' deleted",
"group_deletion_failed": "Could not delete the group '{group}'",
"group_deletion_not_allowed": "The group {group:s} cannot be deleted manually.",
"group_info_failed": "Could not present group info",
"group_deletion_failed": "Could not delete the group '{group}': {error}",
"group_unknown": "The group '{group:s}' is unknown",
"group_updated": "Group '{group}' updated",
"group_update_failed": "Could not update the group '{group}'",
"group_update_failed": "Could not update the group '{group}': {error}",
"group_user_already_in_group": "User {user} is already in group {group}",
"group_user_not_in_group": "User {user} is not in group {group}",
"hook_exec_failed": "Could not run script: {path:s}",
"hook_exec_not_terminated": "Script did not finish properly: {path:s}",
"hook_json_return_error": "Could not read return from hook {path:s}. Error: {msg:s}. Raw content: {raw_content}",
"hook_list_by_invalid": "This property can not be used to list hooks",
"hook_name_unknown": "Unknown hook name '{name:s}'",
"installation_complete": "Installation complete",
"installation_complete": "Installation completed",
"installation_failed": "Something went wrong with the installation",
"invalid_url_format": "Something is wrong with the URL",
"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",
"log_corrupted_md_file": "The YAML metadata file associated with logs is damaged: '{md_file}\nError: {error}'",
@ -261,16 +251,13 @@
"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 display {name} --share' to get help",
"log_does_exists": "There is not operation log with the name '{log}', use 'yunohost log list' to see all available operation logs",
"log_operation_unit_unclosed_properly": "Operation unit has not been closed properly",
"log_app_addaccess": "Add access to '{}'",
"log_app_removeaccess": "Remove access to '{}'",
"log_app_clearaccess": "Remove all access to '{}'",
"log_app_fetchlist": "Add an application list",
"log_app_removelist": "Remove an application list",
"log_app_change_url": "Change the URL of '{}' application",
"log_app_install": "Install the '{}' application",
"log_app_remove": "Remove the '{}' application",
"log_app_upgrade": "Upgrade the '{}' application",
"log_app_makedefault": "Make '{}' the default application",
"log_app_fetchlist": "Add an app list",
"log_app_removelist": "Remove an app list",
"log_app_change_url": "Change the URL of the '{}' app",
"log_app_install": "Install the '{}' app",
"log_app_remove": "Remove the '{}' app",
"log_app_upgrade": "Upgrade the '{}' app",
"log_app_makedefault": "Make '{}' the default app",
"log_available_on_yunopaste": "This log is now available via {url}",
"log_backup_restore_system": "Restore system from a backup archive",
"log_backup_restore_app": "Restore '{}' from a backup archive",
@ -280,21 +267,21 @@
"log_domain_remove": "Remove '{}' domain from system configuration",
"log_dyndns_subscribe": "Subscribe to a YunoHost subdomain '{}'",
"log_dyndns_update": "Update the IP associated with your YunoHost subdomain '{}'",
"log_letsencrypt_cert_install": "Install a Let's encrypt certificate on '{}' domain",
"log_permission_add": "Add the '{}' permission for the app '{}'",
"log_permission_remove": "Remove permission '{}'",
"log_permission_update": "Update permission '{}' for app '{}'",
"log_letsencrypt_cert_install": "Install a Let's Encrypt certificate on '{}' domain",
"log_permission_create": "Create permission '{}'",
"log_permission_delete": "Delete permission '{}'",
"log_permission_url": "Update url related to permission '{}'",
"log_selfsigned_cert_install": "Install self signed certificate on '{}' domain",
"log_letsencrypt_cert_renew": "Renew '{}' Let's encrypt certificate",
"log_letsencrypt_cert_renew": "Renew '{}' Let's Encrypt certificate",
"log_regen_conf": "Regenerate system configurations '{}'",
"log_user_create": "Add '{}' user",
"log_user_delete": "Delete '{}' user",
"log_user_group_add": "Add '{}' group",
"log_user_group_create": "Create '{}' group",
"log_user_group_delete": "Delete '{}' group",
"log_user_group_update": "Update '{}' group",
"log_user_update": "Update user info of '{}'",
"log_user_permission_add": "Update '{}' permission",
"log_user_permission_remove": "Update '{}' permission",
"log_user_permission_update": "Update accesses for permission '{}'",
"log_user_permission_reset": "Reset permission '{}'",
"log_tools_maindomain": "Make '{}' the main domain",
"log_tools_migrations_migrate_forward": "Migrate forward",
"log_tools_postinstall": "Postinstall your YunoHost server",
@ -305,7 +292,7 @@
"ldap_initialized": "LDAP initialized",
"license_undefined": "undefined",
"mail_alias_remove_failed": "Could not remove e-mail alias '{mail:s}'",
"mail_domain_unknown": "Unknown e-mail address for domain '{domain:s}'",
"mail_domain_unknown": "Invalid e-mail address for domain '{domain:s}'. Please, use a domain administrated by this server.",
"mail_forward_remove_failed": "Could not remove e-mail forwarding '{mail:s}'",
"mailbox_disabled": "E-mail turned off for user {user:s}",
"mailbox_used_space_dovecot_down": "The Dovecot mailbox service needs to be up, if you want to fetch used mailbox space",
@ -347,30 +334,31 @@
"migration_0005_postgresql_94_not_installed": "PostgreSQL was not installed on your system. Nothing to do.",
"migration_0005_postgresql_96_not_installed": "PostgreSQL 9.4 is installed, but not postgresql 9.6‽ Something weird might have happened on your system:(…",
"migration_0005_not_enough_space": "Make sufficient space available in {path} to run the migration.",
"migration_0006_disclaimer": "YunoHost now expects admin and root passwords to be synchronized. By running this migration, your root password is going to be replaced by the admin password.",
"migration_0007_cancelled": "YunoHost has failed to improve the way your SSH conf is managed.",
"migration_0006_disclaimer": "YunoHost now expects the admin and root passwords to be synchronized. This migration replaces your root password with the admin password.",
"migration_0007_cancelled": "Could not improve the way your SSH configuration is managed.",
"migration_0007_cannot_restart": "SSH can't be restarted after trying to cancel migration number 6.",
"migration_0008_general_disclaimer": "To improve the security of your server, it is recommended to let YunoHost manage the SSH configuration. Your current SSH setup differs from the recommendation. If you let YunoHost reconfigure it, the way you connect to your server through SSH will change thusly:",
"migration_0008_port": "• You will have to connect using port 22 instead of your current custom SSH port. Feel free to reconfigure it;",
"migration_0008_root": "• You will not be able to connect as root through SSH. Instead you should use the admin user;",
"migration_0008_dsa": "• The DSA key will be turned off. Hence, you might need to invalidate a spooky warning from your SSH client, and recheck the fingerprint of your server;",
"migration_0008_warning": "If you understand those warnings and agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration - though it is not recommended.",
"migration_0008_no_warning": "No major risk indentified concerning overriding your SSH configuration—one can however not be absolutely sure ;)! Run the migration to override it. Otherwise, you can also skip the migration - though it is not recommended.",
"migration_0008_warning": "If you understand those warnings and want YunoHost to override your current configuration, run the migration. Otherwise, you can also skip the migration, though it is not recommended.",
"migration_0008_no_warning": "Overriding your SSH configuration should be safe, though this can not be promised! Run the migration to override it. Otherwise, you can also skip the migration, though it is not recommended.",
"migration_0009_not_needed": "This migration already happened somehow… (?) Skipping.",
"migration_0011_backup_before_migration": "Creating a backup of LDAP database and apps settings prior to the actual migration.",
"migration_0011_can_not_backup_before_migration": "Could not back up the system prior to migration. Error: {error:s}",
"migration_0011_can_not_backup_before_migration": "The backup of the system could not be completed before the migration failed. Error: {error:s}",
"migration_0011_create_group": "Creating a group for each user…",
"migration_0011_done": "Migration successful. You are now able to manage usergroups.",
"migration_0011_LDAP_config_dirty": "It look like that you customized your LDAP configuration. For this migration the LDAP configuration needs to be updated.\nYou need to save your actual configuration, reintialize the original configuration by running 'yunohost tools regen-conf -f' and retry the migration",
"migration_0011_done": "Migration completed. You are now able to manage usergroups.",
"migration_0011_slapd_config_will_be_overwritten": "It looks like you manually edited the slapd configuration. For this critical migration, YunoHost needs to force the update of the slapd configuration. The original files will be backuped in {conf_backup_folder}.",
"migration_0011_LDAP_update_failed": "Could not update LDAP. Error: {error:s}",
"migration_0011_migrate_permission": "Migrating permissions from apps settings to LDAP…",
"migration_0011_migration_failed_trying_to_rollback": "Migration failed… trying to roll back the system.",
"migration_0011_migration_failed_trying_to_rollback": "Could not migrate… trying to roll back the system.",
"migration_0011_rollback_success": "System rolled back.",
"migration_0011_update_LDAP_database": "Updating LDAP database…",
"migration_0011_update_LDAP_schema": "Updating LDAP schema…",
"migration_0011_failed_to_remove_stale_object": "Could not remove stale object {dn}: {error}",
"migrations_already_ran": "Those migrations are already done: {ids}",
"migrations_cant_reach_migration_file": "Could not access migrations files at path %s",
"migrations_dependencies_not_satisfied": "Cannot run migration {id} because first you need to run these migrations: {dependencies_id}",
"migrations_cant_reach_migration_file": "Could not access migrations files at the path '%s'",
"migrations_dependencies_not_satisfied": "Run these migrations: '{dependencies_id}', before migration {id}.",
"migrations_failed_to_load_migration": "Could not load migration {id}: {error}",
"migrations_exclusive_options": "'--auto', '--skip', and '--force-rerun' are mutually exclusive options.",
"migrations_list_conflict_pending_done": "You cannot use both '--previous' and '--done' at the same time.",
@ -379,48 +367,41 @@
"migrations_must_provide_explicit_targets": "You must provide explicit targets when using '--skip' or '--force-rerun'",
"migrations_need_to_accept_disclaimer": "To run the migration {id}, your must accept the following disclaimer:\n---\n{disclaimer}\n---\nIf you accept to run the migration, please re-run the command with the option '--accept-disclaimer'.",
"migrations_no_migrations_to_run": "No migrations to run",
"migrations_no_such_migration": "There is no migration called {id}",
"migrations_no_such_migration": "There is no migration called '{id}'",
"migrations_not_pending_cant_skip": "Those migrations are not pending, so cannot be skipped: {ids}",
"migrations_pending_cant_rerun": "Those migrations are still pending, so cannot be run again: {ids}",
"migrations_running_forward": "Running migration {id}…",
"migrations_skip_migration": "Skipping migration {id}…",
"migrations_success_forward": "Migration {id} completed",
"migrations_to_be_ran_manually": "Migration {id} has to be run manually. Please go to Tools → Migrations on the webadmin page, or run `yunohost tools migrations migrate`.",
"monitor_disabled": "Server monitoring now turned off",
"monitor_enabled": "Server monitoring now turned on",
"monitor_disabled": "Server monitoring now off",
"monitor_enabled": "Server monitoring now on",
"monitor_glances_con_failed": "Could not connect to Glances server",
"monitor_not_enabled": "Server monitoring is off",
"monitor_period_invalid": "Invalid time period",
"monitor_stats_file_not_found": "Statistics file not found",
"monitor_stats_file_not_found": "Could not find the statistics file",
"monitor_stats_no_update": "No monitoring statistics to update",
"monitor_stats_period_unavailable": "No available statistics for the period",
"mountpoint_unknown": "Unknown mountpoint",
"mysql_db_creation_failed": "MySQL database creation failed",
"mysql_db_init_failed": "MySQL database init failed",
"mysql_db_initialized": "The MySQL database now initialized",
"need_define_permission_before": "Redefine the permission using 'yunohost user permission add -u USER' before removing an allowed group",
"mysql_db_creation_failed": "Could not create MySQL database",
"mysql_db_init_failed": "Could not initialize MySQL database",
"mysql_db_initialized": "The MySQL database is now initialized",
"network_check_mx_ko": "DNS MX record is not set",
"network_check_smtp_ko": "Outbound e-mail (SMTP port 25) seems to be blocked by your network",
"network_check_smtp_ok": "Outbound e-mail (SMTP port 25) is not blocked",
"new_domain_required": "You must provide the new main domain",
"no_appslist_found": "No app list found",
"no_internet_connection": "Server not connected to the Internet",
"no_ipv6_connectivity": "IPv6 connectivity is not available",
"no_restore_script": "No restore script found for the app '{app:s}'",
"no_internet_connection": "The server is not connected to the Internet",
"not_enough_disk_space": "Not enough free space on '{path:s}'",
"operation_interrupted": "The operation was manually interrupted?",
"package_unknown": "Unknown package '{pkgname}'",
"packages_upgrade_critical_later": "Critical packages ({packages:s}) will be upgraded later",
"packages_upgrade_failed": "Could not upgrade all the packages",
"password_listed": "This password is among the most used password in the world. Please choose something more unique.",
"password_too_simple_1": "The password needs to be at least 8 characters long",
"password_too_simple_2": "The password needs to be at least 8 characters long and contain a digit, upper and lower characters",
"password_too_simple_3": "The password needs to be at least 8 characters long and contain a digit, upper, lower and special characters",
"password_too_simple_4": "The password needs to be at least 12 characters long and contain a digit, upper, lower and special characters",
"path_removal_failed": "Could not remove path {:s}",
"pattern_backup_archive_name": "Must be a valid filename with max 30 characters, alphanumeric and -_. characters only",
"pattern_domain": "Must be a valid domain name (e.g. my-domain.org)",
"pattern_email": "Must be a valid email address (e.g. someone@domain.org)",
"pattern_email": "Must be a valid e-mail address (e.g. someone@example.com)",
"pattern_firstname": "Must be a valid first name",
"pattern_lastname": "Must be a valid last name",
"pattern_listname": "Must be alphanumeric and underscore characters only",
@ -431,25 +412,27 @@
"pattern_positive_number": "Must be a positive number",
"pattern_username": "Must be lower-case alphanumeric and underscore characters only",
"pattern_password_app": "Sorry, passwords can not contain the following characters: {forbidden_chars}",
"permission_already_clear": "Permission '{permission:s}' already clear for app {app:s}",
"permission_already_exist": "Permission '{permission:s}' for app {app:s} already exist",
"permission_created": "Permission '{permission:s}' for app {app:s} created",
"permission_creation_failed": "Could not grant permission",
"permission_deleted": "Permission '{permission:s}' for app {app:s} deleted",
"permission_deletion_failed": "Missing permission '{permission:s}' to delete the app '{app:s}'",
"permission_not_found": "Permission '{permission:s}' not found for the application '{app:s}'",
"permission_name_not_valid": "Pick an allowed permission name for '{permission:s}'",
"permission_update_failed": "Could not update permission",
"permission_generated": "Permission database updated",
"permission_updated": "Permission '{permission:s}' for the app '{app:s}' updated",
"permission_already_allowed": "Group '{group}' already has permission '{permission}' enabled",
"permission_already_disallowed": "Group '{group}' already has permission '{permission}' disabled'",
"permission_already_exist": "Permission '{permission}' already exists",
"permission_already_up_to_date": "The permission was not updated because the addition/removal requests already match the current state.",
"permission_cannot_remove_main": "Removing a main permission is not allowed",
"permission_created": "Permission '{permission:s}' created",
"permission_creation_failed": "Could not create permission '{permission}': {error}",
"permission_currently_allowed_for_visitors": "This permission is currently granted to visitors in addition to other groups. You probably want to either remove the 'visitors' permission or remove the other groups it is currently granted to.",
"permission_currently_allowed_for_all_users": "This permission is currently granted to all users in addition to other groups. You probably want to either remove the 'all_users' permission or remove the other groups it is currently granted to.",
"permission_deleted": "Permission '{permission:s}' deleted",
"permission_deletion_failed": "Could not delete permission '{permission}': {error}",
"permission_not_found": "Permission '{permission:s}' not found",
"permission_update_failed": "Could not update permission '{permission}' : {error}",
"permission_updated": "Permission '{permission:s}' updated",
"permission_update_nothing_to_do": "No permissions to update",
"permission_require_account": "Permission {permission} only makes sense for users having an account, and therefore cannot be enabled for visitors.",
"port_already_closed": "Port {port:d} is already closed for {ip_version:s} connections",
"port_already_opened": "Port {port:d} is already opened for {ip_version:s} connections",
"port_available": "Port {port:d} is available",
"port_unavailable": "Port {port:d} is not available",
"recommend_to_add_first_user": "The post-install is finished, but YunoHost needs at least one user to work correctly, you should add one using 'yunohost user create <username>' or do it from the admin interface.",
"remove_main_permission_not_allowed": "Removing the main permission is not allowed",
"remove_user_of_group_not_allowed": "You are not allowed to remove the user '{user:s}' in the group '{group:s}'",
"regenconf_file_backed_up": "Configuration file '{conf}' backed up to '{backup}'",
"regenconf_file_copy_failed": "Could not copy the new configuration file '{new}' to '{conf}'",
"regenconf_file_kept_back": "The configuration file '{conf}' is expected to be deleted by regen-conf (category {category}) but was kept back.",
@ -465,7 +448,6 @@
"regenconf_dry_pending_applying": "Checking pending configuration which would have been applied for category '{category}'…",
"regenconf_failed": "Could not regenerate the configuration for category(s): {categories}",
"regenconf_pending_applying": "Applying pending configuration for category '{category}'…",
"restore_action_required": "You must pick something to restore",
"restore_already_installed_app": "An app with the ID '{app:s}' is already installed",
"restore_app_failed": "Could not restore the app '{app:s}'",
"restore_cleaning_failed": "Could not clean up the temporary restoration directory",
@ -475,7 +457,6 @@
"restore_failed": "Could not restore system",
"restore_hook_unavailable": "The restoration script for '{part:s}' not available on your system and not in the archive either",
"restore_may_be_not_enough_disk_space": "Your system seems does not have enough space (free: {free_space:d} B, needed space: {needed_space:d} B, security margin: {margin:d} B)",
"restore_mounting_archive": "Mounting archive into '{path:s}'",
"restore_not_enough_disk_space": "Not enough space (space: {free_space:d} B, needed space: {needed_space:d} B, security margin: {margin:d} B)",
"restore_nothings_done": "Nothing was restored",
"restore_removing_tmp_dir_failed": "Could not remove an old temporary directory",
@ -490,7 +471,7 @@
"server_reboot_confirm": "The server will reboot immediatly, are you sure? [{answers:s}]",
"service_add_failed": "Could not add the service '{service:s}'",
"service_added": "The service '{service:s}' added",
"service_already_started": "The service '{service:s}' has already been started",
"service_already_started": "The service '{service:s}' is running already",
"service_already_stopped": "The service '{service:s}' has already been stopped",
"service_cmd_exec_failed": "Could not execute the command '{command:s}'",
"service_description_avahi-daemon": "Allows you to reach your server using 'yunohost.local' in your local network",
@ -499,10 +480,10 @@
"service_description_fail2ban": "Protects against brute-force and other kinds of attacks from the Internet",
"service_description_glances": "Monitors system info on your server",
"service_description_metronome": "Manage XMPP instant messaging accounts",
"service_description_mysql": "Stores applications data (SQL database)",
"service_description_mysql": "Stores app data (SQL database)",
"service_description_nginx": "Serves or provides access to all the websites hosted on your server",
"service_description_nslcd": "Handles YunoHost user shell connection",
"service_description_php7.0-fpm": "Runs applications written in PHP with NGINX",
"service_description_php7.0-fpm": "Runs apps written in PHP with NGINX",
"service_description_postfix": "Used to send and receive e-mails",
"service_description_redis-server": "A specialized database used for rapid data access, task queue, and communication between programs",
"service_description_rmilter": "Checks various parameters in e-mails",
@ -510,44 +491,40 @@
"service_description_slapd": "Stores users, domains and related info",
"service_description_ssh": "Allows you to connect remotely to your server via a terminal (SSH protocol)",
"service_description_yunohost-api": "Manages interactions between the YunoHost web interface and the system",
"service_description_yunohost-firewall": "Manages open and close connexion ports to services",
"service_description_yunohost-firewall": "Manages open and close connection ports to services",
"service_disable_failed": "Could not turn off the service '{service:s}'\n\nRecent service logs:{logs:s}",
"service_disabled": "'{service:s}' service turned off",
"service_disabled": "The '{service:s}' service was turned off",
"service_enable_failed": "Could not turn on the service '{service:s}'\n\nRecent service logs:{logs:s}",
"service_enabled": "'{service:s}' service turned off",
"service_no_log": "No log to display for service '{service:s}'",
"service_enabled": "The '{service:s}' service was turned off",
"service_no_log": "No logs to display for the service '{service:s}'",
"service_regen_conf_is_deprecated": "'yunohost service regen-conf' is deprecated! Please use 'yunohost tools regen-conf' instead.",
"service_remove_failed": "Could not remove the service '{service:s}'",
"service_removed": "'{service:s}' service removed",
"service_reload_failed": "Could not reload the service '{service:s}'\n\nRecent service logs:{logs:s}",
"service_reloaded": "'{service:s}' service reloaded",
"service_reloaded": "The '{service:s}' service was reloaded",
"service_restart_failed": "Could not restart the service '{service:s}'\n\nRecent service logs:{logs:s}",
"service_restarted": "'{service:s}' service restarted",
"service_reload_or_restart_failed": "Could not reload or restart the service '{service:s}'\n\nRecent service logs:{logs:s}",
"service_reloaded_or_restarted": "'{service:s}' service reloaded or restarted",
"service_reloaded_or_restarted": "The '{service:s}' service was reloaded or restarted",
"service_start_failed": "Could not start the service '{service:s}'\n\nRecent service logs:{logs:s}",
"service_started": "'{service:s}' service started",
"service_status_failed": "Could not determine status of the service '{service:s}'",
"service_stop_failed": "Could not stop the service '{service:s}'\n\nRecent service logs:{logs:s}",
"service_stopped": "'{service:s}' service stopped",
"service_stopped": "The '{service:s}' service stopped",
"service_unknown": "Unknown service '{service:s}'",
"ssowat_conf_generated": "SSOwat configuration generated",
"ssowat_conf_updated": "SSOwat configuration updated",
"ssowat_persistent_conf_read_error": "Could not read persistent SSOwat configuration: {error:s}. Edit /etc/ssowat/conf.json.persistent file to fix the JSON syntax",
"ssowat_persistent_conf_write_error": "Could not save persistent SSOwat configuration: {error:s}. Edit /etc/ssowat/conf.json.persistent file to fix the JSON syntax",
"system_groupname_exists": "Groupname already exists in the system group",
"system_upgraded": "System upgraded",
"system_username_exists": "Username already exists in the list of system users",
"this_action_broke_dpkg": "This action broke dpkg/APT (the system package managers)… You can try to solve this issue by connecting through SSH and running `sudo dpkg --configure -a`.",
"tools_update_failed_to_app_fetchlist": "Could not update YunoHost's applists because: {error}",
"tools_update_failed_to_app_fetchlist": "Could not update YunoHost's app lists because: {error}",
"tools_upgrade_at_least_one": "Please specify '--apps', or '--system'",
"tools_upgrade_cant_both": "Cannot upgrade both system and apps at the same time",
"tools_upgrade_cant_hold_critical_packages": "Could not hold critical packages…",
"tools_upgrade_cant_unhold_critical_packages": "Could not to unhold critical packages…",
"tools_upgrade_cant_unhold_critical_packages": "Could not unhold critical packages…",
"tools_upgrade_regular_packages": "Now upgrading 'regular' (non-yunohost-related) packages…",
"tools_upgrade_regular_packages_failed": "Could not upgrade packages: {packages_list}",
"tools_upgrade_special_packages": "Now upgrading 'special' (yunohost-related) packages…",
"tools_upgrade_special_packages_explanation": "This action will end, but the actual special upgrade will continue in background. Please don't start any other action on your server in the next ~10 minutes (depending on your hardware speed). Once it i done, you may have to log in on the webadmin page again. The upgrade log will be available in Tools → Log (on the webadmin page) or through 'yunohost log list' (from the command line).",
"tools_upgrade_special_packages_explanation": "This action will end, but the actual special upgrade will continue in background. Please don't start any other actions on your server the next ~10 minutes (depending on hardware speed). Once done, you may have to log in on the webadmin page again. The upgrade log will be available in Tools → Log (on the webadmin page) or through 'yunohost log list' (from the command-line).",
"tools_upgrade_special_packages_completed": "YunoHost package upgrade completed.\nPress [Enter] to get the command line back",
"unbackup_app": "App '{app:s}' will not be saved",
"unexpected_error": "Something unexpected went wrong: {error}",
@ -557,29 +534,28 @@
"update_apt_cache_failed": "Could not to update the cache of APT (Debian's package manager). Here is a dump of the sources.list lines, which might help identify problematic lines: \n{sourceslist}",
"update_apt_cache_warning": "Something went wrong while updating the cache of APT (Debian's package manager). Here is a dump of the sources.list lines, which might help identify problematic lines: \n{sourceslist}",
"updating_apt_cache": "Fetching available upgrades for system packages…",
"updating_app_lists": "Fetching available upgrades for applications…",
"updating_app_lists": "Fetching available upgrades for apps…",
"upgrade_complete": "Upgrade complete",
"upgrading_packages": "Upgrading packages…",
"upnp_dev_not_found": "No UPnP device found",
"upnp_disabled": "UPnP turned off",
"upnp_enabled": "UPnP turned on",
"upnp_port_open_failed": "Could not open port via UPnP",
"user_already_in_group": "The user '{user:}' is already in the '{group:s}' group",
"user_already_exists": "The user '{user}' already exists",
"user_created": "User created",
"user_creation_failed": "Could not create user",
"user_creation_failed": "Could not create user {user}: {error}",
"user_deleted": "User deleted",
"user_deletion_failed": "Could not delete user",
"user_deletion_failed": "Could not delete user {user}: {error}",
"user_home_creation_failed": "Could not create 'home' folder for user",
"user_info_failed": "Could not retrieve user info",
"user_not_in_group": "The user '{user:s}' is not in the group {group:s}",
"user_unknown": "Unknown user: {user:s}",
"user_update_failed": "Could not change user info",
"user_update_failed": "Could not update user {user}: {error}",
"user_updated": "User info changed",
"users_available": "Available users:",
"yunohost_already_installed": "YunoHost is already installed",
"yunohost_ca_creation_failed": "Could not create certificate authority",
"yunohost_ca_creation_success": "Local certification authority created.",
"yunohost_configured": "YunoHost now configured",
"yunohost_configured": "YunoHost is now configured",
"yunohost_installing": "Installing YunoHost…",
"yunohost_not_installed": "YunoHost is incorrectly or not correctly installed. Please run 'yunohost tools postinstall'"
"yunohost_not_installed": "YunoHost is not correctly installed. Please run 'yunohost tools postinstall'"
}

View file

@ -1,43 +1,567 @@
{
"admin_password_change_failed": "Malebla ŝanĝi pasvorton",
"admin_password_changed": "Pasvorto de la estro estas ŝanĝita",
"admin_password_change_failed": "Ne eblas ŝanĝi pasvorton",
"admin_password_changed": "La pasvorto de administrado ŝanĝiĝis",
"app_already_installed": "{app:s} estas jam instalita",
"app_already_up_to_date": "{app:s} estas ĝisdata",
"app_already_up_to_date": "{app:s} estas jam ĝisdata",
"app_argument_required": "Parametro {name:s} estas bezonata",
"app_change_url_identical_domains": "Malnovaj kaj novaj domajno/URL estas la sama ('{domain:s}{path:s}'), nenio fareblas.",
"app_change_url_success": "URL de appo {app:s} ŝanĝita al {domain:s}{path:s}",
"app_extraction_failed": "Malebla malkompaktigi instaldosierojn",
"app_id_invalid": "Nevalida apo id",
"app_change_url_success": "{app:s} URL nun estas {domain:s} {path:s}",
"app_extraction_failed": "Ne povis ĉerpi la instalajn dosierojn",
"app_id_invalid": "Nevalida apo ID",
"app_incompatible": "Apo {app} ne estas kongrua kun via YunoHost versio",
"app_install_files_invalid": "Nevalidaj instaldosieroj",
"app_location_already_used": "Apo {app} jam estas instalita al tiu loco ({path})",
"user_updated": "Uzanto estas ĝisdatita",
"app_install_files_invalid": "Ĉi tiuj dosieroj ne povas esti instalitaj",
"app_location_already_used": "La app '{app}' jam estas instalita en ({path})",
"user_updated": "Uzantinformoj ŝanĝis",
"users_available": "Uzantoj disponeblaj :",
"yunohost_already_installed": "YunoHost estas jam instalita",
"yunohost_ca_creation_failed": "Ne eblas krei atestan aŭtoritaton",
"yunohost_ca_creation_success": "Loka atesta aŭtoritato estas kreita.",
"yunohost_ca_creation_failed": "Ne povis krei atestan aŭtoritaton",
"yunohost_ca_creation_success": "Loka atestila aŭtoritato kreiĝis.",
"yunohost_installing": "Instalante YunoHost…",
"service_description_glances": "monitoras sisteminformojn de via servilo",
"service_description_metronome": "mastrumas XMPP tujmesaĝilon kontojn",
"service_description_mysql": "stokas aplikaĵojn datojn (SQL datumbazo)",
"service_description_nginx": "servas aŭ permesas atingi ĉiujn retejojn gastigita sur via servilo",
"service_description_nslcd": "mastrumas Yunohost uzantojn konektojn per komanda linio",
"service_description_php7.0-fpm": "rulas aplikaĵojn skibita en PHP kun nginx",
"service_description_postfix": "uzita por sendi kaj ricevi retpoŝtojn",
"service_description_redis-server": "specialita datumbazo uzita por rapida datumo atingo, atendovicoj kaj komunikadoj inter programoj",
"service_description_rmilter": "kontrolas diversajn parametrojn en retpoŝtoj",
"service_description_rspamd": "filtras trudmesaĝojn, kaj aliaj funkcioj rilate al retpoŝto",
"service_description_slapd": "stokas uzantojn, domajnojn kaj rilatajn informojn",
"service_description_ssh": "permesas al vi konekti al via servilo kun fora terminalo (SSH protokolo)",
"service_description_yunohost-api": "mastrumas interagojn inter la YunoHost retinterfaco kaj la sistemo",
"service_description_yunohost-firewall": "mastrumas malfermitajn kaj fermitajn konektejojn al servoj",
"service_disable_failed": "Neebla malaktivigi servon '{service:s}'\n\nFreŝaj protokoloj de la servo : {logs:s}",
"service_disabled": "Servo '{service:s}' estas malaktivigita",
"service_description_glances": "Monitoras sistemajn informojn en via servilo",
"service_description_metronome": "Mastrumas XMPP tujmesaĝilon kontojn",
"service_description_mysql": "Stokas aplikaĵojn datojn (SQL datumbazo)",
"service_description_nginx": "Servas aŭ permesas atingi ĉiujn retejojn gastigita sur via servilo",
"service_description_nslcd": "Mastrumas Yunohost uzantojn konektojn per komanda linio",
"service_description_php7.0-fpm": "Rulas aplikaĵojn skibita en PHP kun nginx",
"service_description_postfix": "Uzita por sendi kaj ricevi retpoŝtojn",
"service_description_redis-server": "Specialita datumbazo uzita por rapida datumo atingo, atendovicoj kaj komunikadoj inter programoj",
"service_description_rmilter": "Kontrolas diversajn parametrojn en retpoŝtoj",
"service_description_rspamd": "Filtras trudmesaĝojn, kaj aliaj funkcioj rilate al retpoŝto",
"service_description_slapd": "Stokas uzantojn, domajnojn kaj rilatajn informojn",
"service_description_ssh": "Permesas al vi konekti al via servilo kun fora terminalo (SSH protokolo)",
"service_description_yunohost-api": "Mastrumas interagojn inter la YunoHost retinterfaco kaj la sistemo",
"service_description_yunohost-firewall": "Mastrumas malfermitajn kaj fermitajn konektejojn al servoj",
"service_disable_failed": "Ne povis malŝalti la servon '{service:s}'\n\nFreŝaj protokoloj de la servo : {logs:s}",
"service_disabled": "'{service: s}' servo malŝaltita",
"action_invalid": "Nevalida ago « {action:s} »",
"admin_password": "Pasvorto de la estro",
"admin_password_too_long": "Bonvolu elekti pasvorton pli mallonga ol 127 signoj",
"already_up_to_date": "Neniu estas farenda! Ĉiu jam estas ĝisdata!",
"app_argument_choice_invalid": "Nevalida elekto por argumento « {name:s} », ĝi devas esti unu el {choices:s}",
"app_argument_invalid": "Nevalida valoro por argumento « {name:s} » : {error:s}",
"app_change_url_failed_nginx_reload": "Reŝargi nginx malsuksesis. Jen la eligo de « nginx -t » :\n{nginx_errors:s}"
"already_up_to_date": "Nenio por fari. Ĉio estas jam ĝisdatigita.",
"app_argument_choice_invalid": "Uzu unu el ĉi tiuj elektoj '{choices:s}' por la argumento '{name:s}'",
"app_argument_invalid": "Elektu validan valoron por la argumento '{name:s}': {error:s}",
"app_change_url_failed_nginx_reload": "Ne eblis reŝarĝi NGINX. Jen la eligo de 'nginx -t':\n{nginx_errors:s}",
"appslist_url_already_tracked": "Jam ekzistas registrita app-listo kun la URL {url:s}.",
"ask_new_admin_password": "Nova administrada pasvorto",
"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",
"backup_archive_system_part_not_available": "Sistemo parto '{part:s}' ne haveblas en ĉi tiu rezervo",
"apps_permission_not_found": "Neniu permeso trovita por la instalitaj programoj",
"apps_permission_restoration_failed": "Donu la rajtigan permeson '{permission:s}' por restarigi {app:s}",
"backup_abstract_method": "Ĉi tiu rezerva metodo ankoraŭ efektiviĝis",
"apps_already_up_to_date": "Ĉiuj aplikoj estas jam ĝisdatigitaj",
"backup_borg_not_implemented": "La kopia metodo de Borg ankoraŭ ne estas efektivigita",
"app_upgrade_stopped": "Ĝisdatigi ĉiujn aplikaĵojn estis ĉesigita por eviti eblajn damaĝojn ĉar unu app ne povis esti altgradigita",
"app_location_unavailable": "Ĉi tiu URL aŭ ne haveblas, aŭ konfliktas kun la jam instalita (j) apliko (j):\n{apps:s}",
"backup_archive_app_not_found": "Ne povis trovi la programon '{app:s}' en la rezerva ar archiveivo",
"backup_actually_backuping": "Krei rezervan ar archiveivon el la kolektitaj dosieroj …",
"backup_method_borg_finished": "Sekurkopio en Borg finiĝis",
"appslist_removed": "La listo de '{appslist:s}' estis forigita",
"app_change_url_no_script": "La app '{app_name:s}' ankoraŭ ne subtenas URL-modifon. Eble vi devus altgradigi ĝin.",
"app_start_install": "Instali la programon '{app}' …",
"backup_created": "Sekurkopio kreita",
"app_make_default_location_already_used": "Ne povas igi la aplikon '{app}' defaŭlta sur la domajno, '{domain}' jam uziĝas de la alia app '{other_app}'",
"backup_method_copy_finished": "Rezerva kopio finis",
"app_not_properly_removed": "{app:s} ne estis ĝuste forigita",
"backup_archive_broken_link": "Ne povis aliri la rezervan ar archiveivon (rompita ligilo al {path:s})",
"app_requirements_checking": "Kontrolante postulatajn pakaĵojn por {app} …",
"app_not_installed": "Ne povis trovi la aplikon '{app:s}' en la listo de instalitaj programoj: {all_apps}",
"app_location_install_failed": "Ne eblas instali la aplikon tie ĉar ĝi konfliktas kun la '{other_app}' jam instalita en '{other_path}'",
"ask_new_path": "Nova vojo",
"backup_custom_mount_error": "Propra rezerva metodo ne povis preterpasi la paŝon 'monto'",
"app_upgrade_app_name": "Nun ĝisdatiganta {app} …",
"app_manifest_invalid": "Io misas pri la aplika manifesto: {error}",
"backup_cleaning_failed": "Ne povis purigi la provizoran rezervan dosierujon",
"backup_invalid_archive": "Ĉi tio ne estas rezerva ar archiveivo",
"ask_current_admin_password": "Pasvorto pri aktuala administrado",
"backup_creation_failed": "Ne povis krei la rezervan ar archiveivon",
"backup_hook_unknown": "La rezerva hoko '{hoko:s}' estas nekonata",
"backup_custom_backup_error": "Propra rezerva metodo ne povis preterpasi la paŝon \"sekurkopio\"",
"ask_main_domain": "Ĉefa domajno",
"backup_method_tar_finished": "TAR-rezerva ar archiveivo kreita",
"appslist_unknown": "La app-listo '{appslist:s}' estas nekonata.",
"ask_list_to_remove": "Listo por forigi",
"backup_cant_mount_uncompress_archive": "Ne povis munti la nekompresitan ar archiveivon kiel protektita kontraŭ skribo",
"appslist_retrieve_bad_format": "Ne povis legi la elprenitan liston '{appslist:s}'",
"appslist_corrupted_json": "Ne povis ŝarĝi la aplikajn listojn. Ĝi aspektas kiel {filename:s} estas damaĝita.",
"app_action_cannot_be_ran_because_required_services_down": "Ĉi tiuj postulataj servoj devas funkcii por funkciigi ĉi tiun agon: {services}. Provu rekomenci ilin por daŭrigi (kaj eble esploru, kial ili malsupreniras).",
"backup_copying_to_organize_the_archive": "Kopiante {size:s} MB por organizi la ar archiveivon",
"backup_output_directory_forbidden": "Elektu malsaman elirejan dosierujon. Sekurkopioj ne povas esti kreitaj en sub-dosierujoj / bin, / boot, / dev, / ktp, / lib, / root, / run, / sbin, / sys, / usr, / var aŭ /home/yunohost.backup/archives",
"appslist_could_not_migrate": "Ne povis migri la liston de aplikoj '{appslist:s}'! Ne eblis analizi la URL ... La malnova cron-laboro konserviĝis en {bkp_file:s}.",
"app_requirements_failed": "Certaines exigences ne sont pas remplies pour {app}: {error}",
"backup_no_uncompress_archive_dir": "Ne ekzistas tia nekompremita arkiva dosierujo",
"password_too_simple_1": "Pasvorto devas esti almenaŭ 8 signojn longa",
"app_upgrade_failed": "Ne povis ĝisdatigi {app:s}",
"app_upgrade_several_apps": "La sekvaj apliko estos altgradigitaj: {apps}",
"backup_archive_open_failed": "Ne povis malfermi la rezervan ar archiveivon",
"ask_lastname": "Familia nomo",
"app_start_backup": "Kolekti dosierojn por esti subtenata por la '{app}' …",
"backup_archive_name_exists": "Rezerva arkivo kun ĉi tiu nomo jam ekzistas.",
"backup_applying_method_tar": "Krei la rezervan TAR-ar archiveivon …",
"backup_method_custom_finished": "Propra rezerva metodo '{metodo:s}' finiĝis",
"appslist_retrieve_error": "Ne eblas akiri la forajn listojn '{appslist:s}': {eraro:s}",
"app_already_installed_cant_change_url": "Ĉi tiu app estas jam instalita. La URL ne povas esti ŝanĝita nur per ĉi tiu funkcio. Rigardu \"app changeurl\" se ĝi haveblas.",
"app_not_correctly_installed": "{app:s} ŝajnas esti malĝuste instalita",
"app_removed": "{app:s} forigita",
"backup_delete_error": "Ne povis forigi '{path: s}'",
"app_package_need_update": "La pakaĵo {app} devas esti ĝisdatigita por sekvi YunoHost-ŝanĝojn",
"backup_nothings_done": "Nenio por ŝpari",
"backup_applying_method_custom": "Nomante la kutiman rezervan metodon '{metodo:s}' …",
"appslist_fetched": "Ĝisdatigis la liston de aplikoj '{appslist:s}'",
"backup_app_failed": "Ne eblis rezervi la programon '{app:s}'",
"app_upgrade_some_app_failed": "Iuj aplikoj ne povis esti altgradigitaj",
"app_start_remove": "Forigo de la apliko '{app}' …",
"backup_output_directory_not_empty": "Vi devas elekti malplenan eligitan dosierujon",
"backup_archive_writing_error": "Ne povis aldoni la dosierojn '{source:s}' (nomitaj en la ar theivo '{dest:s}') por esti rezervitaj en la kunpremita arkivo '{archive:s}'",
"ask_email": "Retpoŝta adreso",
"app_start_restore": "Restarigi la programon '{app}' …",
"backup_applying_method_copy": "Kopiante ĉiujn dosierojn al sekurkopio …",
"backup_couldnt_bind": "Ne povis ligi {src:s} al {dest:s}.",
"ask_password": "Pasvorto",
"app_requirements_unmeet": "Postuloj ne estas renkontitaj por {app}, la pakaĵo {pkgname} ({version}) devas esti {spec}",
"ask_firstname": "Antaŭnomo",
"backup_ask_for_copying_if_needed": "Ĉu vi volas realigi la sekurkopion uzante {size:s} MB provizore? (Ĉi tiu maniero estas uzata ĉar iuj dosieroj ne povus esti pretigitaj per pli efika metodo.)",
"backup_mount_archive_for_restore": "Preparante arkivon por restarigo …",
"appslist_migrating": "Migrado de la aplika listo '{appslist:s}' …",
"backup_csv_creation_failed": "Ne povis krei la CSV-dosieron bezonatan por restarigo",
"backup_archive_name_unknown": "Nekonata loka rezerva ar archiveivo nomata '{name:s}'",
"backup_applying_method_borg": "Sendado de ĉiuj dosieroj al sekurkopio en borg-rezerva deponejo …",
"app_sources_fetch_failed": "Ne povis akiri fontajn dosierojn, ĉu la URL estas ĝusta?",
"appslist_name_already_tracked": "Registrita aplika listo kun la nomo {name:s} jam ekzistas.",
"ask_new_domain": "Nova domajno",
"app_unknown": "Nekonata apliko",
"app_not_upgraded": "La aplikaĵo '{failed_app}' ne ĝisdatigis, kaj pro tio la sekvaj ĝisdatigoj de aplikoj estis nuligitaj: {apps}",
"aborting": "Aborti.",
"ask_path": "Pado",
"app_upgraded": "{app:s} altgradigita",
"backup_deleted": "Rezerva forigita",
"backup_csv_addition_failed": "Ne povis aldoni dosierojn al sekurkopio en la CSV-dosiero",
"dpkg_lock_not_available": "Ĉi tiu komando ne povas funkcii nun ĉar alia programo uzas la seruron de dpkg (la administrilo de paka sistemo)",
"migration_0003_yunohost_upgrade": "Komenci la ĝisdatigon de YunoHost-pako ... La migrado finiĝos, sed la efektiva ĝisdatigo okazos tuj poste. Post kiam la operacio finiĝos, vi eble devos ensaluti denove sur la retpaĝo.",
"domain_dyndns_root_unknown": "Nekonata radika domajno DynDNS",
"field_invalid": "Nevalida kampo '{:s}'",
"log_app_makedefault": "Faru '{}' la defaŭlta apliko",
"migration_0003_still_on_jessie_after_main_upgrade": "Io okazis malbone dum la ĉefa ĝisdatigo: Ĉu la sistemo ankoraŭ estas en Jessie‽ Por esplori la aferon, bonvolu rigardi {log}:s …",
"migration_0011_can_not_backup_before_migration": "La sekurkopio de la sistemo antaŭ la migrado malsukcesis. Migrado malsukcesis. Eraro: {error:s}",
"migration_0011_create_group": "Krei grupon por ĉiu uzanto…",
"backup_system_part_failed": "Ne eblis sekurkopi la sistemon de '{part:s}'",
"global_settings_setting_security_postfix_compatibility": "Kongruo vs sekureca kompromiso por la Postfix-servilo. Afektas la ĉifradojn (kaj aliajn aspektojn pri sekureco)",
"group_unknown": "La grupo '{group:s}' estas nekonata",
"mailbox_disabled": "Retpoŝto malŝaltita por uzanto {user:s}",
"migration_description_0011_setup_group_permission": "Agordu uzantogrupon kaj starigu permeson por programoj kaj servoj",
"migration_0011_backup_before_migration": "Krei sekurkopion de LDAP-datumbazo kaj agordojn antaŭ la efektiva migrado.",
"migration_0011_LDAP_config_dirty": "Similas ke vi agordis vian LDAP-agordon. Por ĉi tiu migrado la LDAP-agordo bezonas esti ĝisdatigita.\nVi devas konservi vian aktualan agordon, reintaligi la originalan agordon per funkciado de \"yunohost iloj regen-conf -f\" kaj reprovi la migradon",
"migration_0011_migrate_permission": "Migrado de permesoj de agordoj al aplikoj al LDAP…",
"migration_0011_migration_failed_trying_to_rollback": "Migrado malsukcesis ... provante reverti la sistemon.",
"migrations_dependencies_not_satisfied": "Ne eblas kuri migradon {id} ĉar unue vi devas ruli ĉi tiujn migradojn: {dependencies_id}",
"migrations_failed_to_load_migration": "Ne povis ŝarĝi migradon {id}: {error}",
"migrations_exclusive_options": "'--auto', '--skip' kaj '--force-rerun' estas reciproke ekskluzivaj ebloj.",
"migrations_must_provide_explicit_targets": "Vi devas provizi eksplicitajn celojn kiam vi uzas '--skip' aŭ '--force-rerun'",
"permission_update_failed": "Ne povis ĝisdatigi permeson '{permission}': {error}",
"permission_updated": "Ĝisdatigita \"{permission:s}\" rajtigita",
"permission_update_nothing_to_do": "Neniuj permesoj ĝisdatigi",
"tools_upgrade_cant_hold_critical_packages": "Ne povis teni kritikajn pakojn…",
"upnp_dev_not_found": "Neniu UPnP-aparato trovita",
"migration_description_0012_postgresql_password_to_md5_authentication": "Devigu PostgreSQL-aŭtentigon uzi MD5 por lokaj ligoj",
"migration_0011_done": "Migrado sukcesis. Vi nun kapablas administri uzantajn grupojn.",
"migration_0011_LDAP_update_failed": "Ne povis ĝisdatigi LDAP. Eraro: {error:s}",
"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!",
"service_remove_failed": "Ne povis forigi la servon '{service:s}'",
"migration_0003_fail2ban_upgrade": "Komenci la ĝisdatigon Fail2Ban…",
"backup_permission": "Rezerva permeso por app {app:s}",
"log_user_group_delete": "Forigi grupon '{}'",
"log_user_group_update": "Ĝisdatigi grupon '{}'",
"migration_0005_postgresql_94_not_installed": "PostgreSQL ne estis instalita en via sistemo. Nenio por fari.",
"dyndns_provider_unreachable": "Ne povas atingi Dyndns-provizanton {provider}: ĉu via YunoHost ne estas ĝuste konektita al la interreto aŭ la dynette-servilo malŝaltiĝas.",
"good_practices_about_user_password": "Vi nun estas por difini novan uzantan pasvorton. La pasvorto devas esti almenaŭ 8 signoj - kvankam estas bone praktiki uzi pli longan pasvorton (t.e. pasfrazon) kaj / aŭ variaĵon de signoj (majuskloj, minuskloj, ciferoj kaj specialaj signoj).",
"group_updated": "Ĝisdatigita \"{group}\" grupo",
"group_already_exist": "Grupo {group} jam ekzistas",
"group_already_exist_on_system": "Grupo {group} jam ekzistas en la sistemaj grupoj",
"group_cannot_be_edited": "La grupo {group} ne povas esti redaktita permane.",
"group_cannot_be_deleted": "La grupo {group} ne povas esti forigita permane.",
"group_update_failed": "Ne povis ĝisdatigi la grupon '{group}': {error}",
"group_user_already_in_group": "Uzanto {user} jam estas en grupo {group}",
"group_user_not_in_group": "Uzanto {user} ne estas en grupo {group}",
"installation_complete": "Kompleta instalado",
"log_category_404": "La loga kategorio '{category}' ne ekzistas",
"log_permission_create": "Krei permeson '{}'",
"log_permission_delete": "Forigi permeson '{}'",
"log_permission_urls": "Ĝisdatigu URLojn rilatajn al permeso '{}'",
"log_user_group_create": "Krei grupon '{}'",
"log_user_permission_update": "Mise à jour des accès pour la permission '{}'",
"log_user_permission_reset": "Restarigi permeson '{}'",
"mail_forward_remove_failed": "Ne povis forigi retpoŝton plusendante '{mail:s}'",
"migration_0011_rollback_success": "Sistemo ruliĝis reen.",
"migration_0011_update_LDAP_database": "Ĝisdatigante LDAP-datumbazon…",
"migration_0011_update_LDAP_schema": "Ĝisdatigante LDAP-skemon…",
"migration_0011_failed_to_remove_stale_object": "Malsukcesis forigi neokazan objekton {dn}: {error}",
"migrations_already_ran": "Tiuj migradoj estas jam faritaj: {ids}",
"migrations_no_such_migration": "Estas neniu migrado nomata {id}",
"permission_already_allowed": "Grupo '{group}' jam havas permeson '{permission}' ebligita'",
"permission_already_disallowed": "Grupo '{group}' jam havas permeson '{permission}' malebligita'",
"permission_cannot_remove_main": "Forigo de ĉefa permeso ne rajtas",
"permission_creation_failed": "Ne povis krei permeson '{permission}': {error}",
"tools_update_failed_to_app_fetchlist": "Ne povis ĝisdatigi la aparatojn de YunoHost ĉar: {error}",
"user_already_exists": "Uzanto {uzanto} jam ekzistas",
"migrations_pending_cant_rerun": "Tiuj migradoj ankoraŭ estas pritraktataj, do ne plu rajtas esti ekzekutitaj: {ids}",
"migrations_running_forward": "Kuranta migrado {id}…",
"migrations_success_forward": "Migrado {id} kompletigita",
"operation_interrupted": "La operacio estis permane interrompita?",
"permission_created": "Permesita '{permission:s}' kreita",
"permission_deleted": "Permesita \"{permission:s}\" forigita",
"permission_deletion_failed": "Ne povis forigi permeson '{permission}': {error}",
"permission_not_found": "Permesita \"{permission:s}\" ne trovita",
"restore_not_enough_disk_space": "Ne sufiĉa spaco (spaco: {free_space:d} B, necesa spaco: {needed_space:d} B, sekureca marĝeno: {margin:d} B)",
"tools_upgrade_regular_packages": "Nun ĝisdatigi 'regulajn' (ne-yunohost-rilatajn) pakojn …",
"tools_upgrade_special_packages_explanation": "Ĉi tiu ago finiĝos, sed la fakta speciala ĝisdatigo daŭros en fono. Bonvolu ne komenci iun alian agon en via servilo en la sekvaj ~ 10 minutoj (depende de via aparata rapideco). Unufoje mi plenumis, vi eble devos ensaluti en la retpaĝo. La ĝisdatiga registro estos havebla en Iloj → Madero (sur la retpaĝo) aŭ tra 'yunohost-registro-listo' (el la komandlinio).",
"unrestore_app": "App '{app:s}' ne restarigos",
"group_created": "Grupo '{group}' kreita",
"group_creation_failed": "Ne povis krei la grupon '{group}': {error}",
"group_deleted": "Grupo '{group}' forigita",
"group_deletion_failed": "Ne povis forigi la grupon '{group}': {error}",
"migrations_not_pending_cant_skip": "Tiuj migradoj ankoraŭ ne estas pritraktataj, do ne eblas preterlasi: {ids}",
"permission_already_exist": "Permesita '{permission}' jam ekzistas",
"domain_created": "Domajno kreita",
"migrate_tsig_wait_2": "2 minutoj …",
"log_user_create": "Aldonu uzanton '{}'",
"ip6tables_unavailable": "Vi ne povas ludi kun ip6tabloj ĉi tie. Vi estas en ujo aŭ via kerno ne subtenas ĝin",
"mail_unavailable": "Ĉi tiu retpoŝta adreso estas rezervita kaj aŭtomate estos atribuita al la unua uzanto",
"certmanager_domain_dns_ip_differs_from_public_ip": "La DNS 'A' rekordo por la domajno '{domain:s}' diferencas de ĉi tiu IP-servilo. Se vi lastatempe modifis vian A-registron, bonvolu atendi ĝin propagandi (iuj DNS-disvastigaj kontroliloj estas disponeblaj interrete). (Se vi scias, kion vi faras, uzu '--no-checks' por malŝalti tiujn ĉekojn.)",
"tools_upgrade_special_packages_completed": "Plenumis la ĝisdatigon de pakaĵoj de YunoHost.\nPremu [Enter] por retrovi la komandlinion",
"log_remove_on_failed_install": "Forigu '{}' post malsukcesa instalado",
"regenconf_file_manually_modified": "La agorddosiero '{conf}' estis modifita permane kaj ne estos ĝisdatigita",
"regenconf_would_be_updated": "La agordo estus aktualigita por la kategorio '{category}'",
"certmanager_cert_install_success_selfsigned": "Mem-subskribita atestilo nun instalita por la domajno '{domain:s}'",
"global_settings_unknown_setting_from_settings_file": "Nekonata ŝlosilo en agordoj: '{setting_key:s}', forĵetu ĝin kaj konservu ĝin en /etc/yunohost/settings-unknown.json",
"regenconf_file_backed_up": "Agordodosiero '{conf}' estis rezervita al '{backup}'",
"migration_0007_cannot_restart": "SSH ne rekomencas post provi nuligi la migradan numeron 6.",
"migration_description_0006_sync_admin_and_root_passwords": "Sinkronigu admin kaj radikajn pasvortojn",
"updating_app_lists": "Akirante haveblajn ĝisdatigojn por aplikoj…",
"iptables_unavailable": "Vi ne povas ludi kun iptables ĉi tie. Vi estas en ujo aŭ via kerno ne subtenas ĝin",
"global_settings_cant_write_settings": "Ne eblis konservi agordojn, tial: {reason:s}",
"service_added": "La servo '{service:s}' aldonis",
"upnp_disabled": "UPnP malŝaltis",
"service_started": "Servo '{service:s}' komenciĝis",
"port_already_opened": "Haveno {port:d} estas jam malfermita por {ip_version:s} rilatoj",
"installation_failed": "Io okazis malbone kun la instalado",
"network_check_mx_ko": "DNS MX-rekordo ne estas agordita",
"migrate_tsig_wait_3": "1 minuto …",
"certmanager_conflicting_nginx_file": "Ne povis prepari domajnon por ACME-defio: la agordo de NGINX {filepath:s} konfliktas kaj unue devas esti forigita",
"upgrading_packages": "Ĝisdatigi pakojn…",
"custom_app_url_required": "Vi devas provizi URL por altgradigi vian kutimon app {app: s}",
"service_reload_failed": "Ne povis reŝargi la servon '{service:s}'\n\nLastatempaj servaj protokoloj: {logs:s}",
"packages_upgrade_failed": "Ne povis ĝisdatigi ĉiujn pakojn",
"hook_json_return_error": "Ne povis legi revenon de hoko {path:s}. Eraro: {msg:s}. Kruda enhavo: {raw_content}",
"dyndns_cron_removed": "DynDNS cron-laboro forigita",
"dyndns_key_not_found": "DNS-ŝlosilo ne trovita por la domajno",
"custom_appslist_name_required": "Vi devas doni nomon por via kutima app-listo",
"tools_upgrade_regular_packages_failed": "Ne povis ĝisdatigi pakojn: {packages_list}",
"service_start_failed": "Ne povis komenci la servon '{service:s}'\n\nLastatempaj servaj protokoloj: {logs:s}",
"service_reloaded": "Servo '{service:s}' reŝargita",
"system_upgraded": "Sistemo ĝisdatigita",
"domain_deleted": "Domajno forigita",
"certmanager_acme_not_configured_for_domain": "Atestilo por la domajno '{domain:s}' ne ŝajnas esti ĝuste instalita. Bonvolu ekzekuti 'cert-instali' por ĉi tiu regado unue.",
"migration_description_0009_decouple_regenconf_from_services": "Malkonstruu la regen-konf-mekanismon de servoj",
"user_update_failed": "Ne povis ĝisdatigi uzanton {user}: {error}",
"migration_description_0008_ssh_conf_managed_by_yunohost_step2": "Lasu la SSH-agordon estu administrata de YunoHost (paŝo 2, manlibro)",
"restore_confirm_yunohost_installed": "Ĉu vi vere volas restarigi jam instalitan sistemon? [{answers:s}]",
"pattern_positive_number": "Devas esti pozitiva nombro",
"monitor_stats_file_not_found": "Statistika dosiero ne trovita",
"certmanager_error_no_A_record": "Neniu DNS 'A' rekordo trovita por '{domain:s}'. Vi bezonas atentigi vian domajnan nomon al via maŝino por povi instali atestilon Lasu-Ĉifri. (Se vi scias, kion vi faras, uzu '--no-checks' por malŝalti tiujn ĉekojn.)",
"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{sourcelist}",
"migrations_no_migrations_to_run": "Neniuj migradoj por funkcii",
"executing_command": "Plenumanta komandon '{command:s}' …",
"diagnosis_no_apps": "Neniu tia instalita app",
"certmanager_attempt_to_renew_nonLE_cert": "La atestilo por la domajno '{domain:s}' ne estas elsendita de Let's Encrypt. Ne eblas renovigi ĝin aŭtomate!",
"global_settings_setting_example_bool": "Ekzemplo bulea elekto",
"domain_dyndns_already_subscribed": "Vi jam abonis DynDNS-domajnon",
"log_letsencrypt_cert_renew": "Renovigu '{}' Let's Encrypt atestilon",
"migrate_tsig_start": "Detektita ŝlosila algoritmo nesufiĉa por TSIG-subskribo de la domajno '{domain}', komencanta migradon al la pli sekura HMAC-SHA-512",
"ldap_init_failed_to_create_admin": "LDAP-iniciato ne povis krei administran uzanton",
"backup_output_directory_required": "Vi devas provizi elirejan dosierujon por la sekurkopio",
"tools_upgrade_cant_unhold_critical_packages": "Ne povis malhelpi kritikajn pakojn…",
"diagnosis_monitor_disk_error": "Ne povis monitori diskojn: {error}",
"log_link_to_log": "Plena ŝtipo de ĉi tiu operacio: '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\"> {desc} </a>'",
"service_no_log": "Neniu registro por montri por servo '{service:s}'",
"global_settings_cant_serialize_settings": "Ne eblis serialigi datumojn pri agordoj, motivo: {reason:s}",
"backup_running_hooks": "Kurado de apogaj hokoj …",
"package_not_installed": "Pako '{pkgname}' ne estas instalita",
"certmanager_domain_unknown": "Nekonata domajno '{domain:s}'",
"unexpected_error": "Io neatendita iris malbone: {error}",
"password_listed": "Ĉi tiu pasvorto estas inter la plej uzataj pasvortoj en la mondo. Bonvolu elekti ion pli unikan.",
"ssowat_persistent_conf_write_error": "Ne povis konservi konstantan SSOwat-agordon: {error:s}. Redakti /etc/ssowat/conf.json.persistent dosiero por ripari la Jaks-sintakson",
"migration_description_0007_ssh_conf_managed_by_yunohost_step1": "Lasu la SSH-agordon estu administrata de YunoHost (paŝo 1, aŭtomata)",
"migration_0009_not_needed": "Ĉi tiu migrado jam iel okazis ... (?) Saltado.",
"ssowat_conf_generated": "SSOwat-agordo generita",
"migrate_tsig_wait": "Atendante tri minutojn por ke la servilo DynDNS enkalkulu la novan ŝlosilon …",
"log_remove_on_failed_restore": "Forigu '{}' post malsukcesa restarigo de rezerva ar archiveivo",
"dpkg_is_broken": "Vi ne povas fari ĉi tion nun ĉar dpkg/APT (la administrantoj pri pakaĵaj sistemoj) ŝajnas esti rompita stato ... Vi povas provi solvi ĉi tiun problemon per konekto per SSH kaj funkcianta `sudo dpkg --configure -a`.",
"recommend_to_add_first_user": "La postinstalo finiĝis, sed YunoHost bezonas almenaŭ unu uzanton por funkcii ĝuste, vi devas aldoni unu uzante 'yunohost user create <username>' aŭ fari ĝin de la administra interfaco.",
"certmanager_cert_signing_failed": "Ne povis subskribi la novan atestilon",
"migration_description_0003_migrate_to_stretch": "Altgradigu la sistemon al Debian Stretch kaj YunoHost 3.0",
"log_tools_upgrade": "Ĝisdatigu sistemajn pakaĵojn",
"network_check_smtp_ko": "Ekstera retpoŝto (SMTP-haveno 25) ŝajnas esti blokita de via reto",
"log_available_on_yunopaste": "Ĉi tiu protokolo nun haveblas per {url}",
"certmanager_http_check_timeout": "Ekdifinita kiam servilo provis kontakti sin per HTTP per publika IP-adreso (domajno '{domain:s}' kun IP '{ip:s}'). Vi eble spertas haŭtoproblemon, aŭ la fajroŝirmilo / enkursigilo antaŭ via servilo miskonfiguras.",
"pattern_port_or_range": "Devas esti valida haveno-nombro (t.e. 0-65535) aŭ gamo da havenoj (t.e. 100:200)",
"migrations_loading_migration": "Ŝarĝante migradon {id}…",
"port_available": "Haveno {port:d} estas havebla",
"pattern_mailbox_quota": "Devas esti grandeco kun la sufikso b/k/M/G/T aŭ 0 por ne havi kvoton",
"migration_0008_general_disclaimer": "Por plibonigi la sekurecon de via servilo, rekomendas lasi YunoHost administri la SSH-agordon. Via nuna SSH-aranĝo diferencas de la rekomendo. Se vi lasas YunoHost agordi ĝin, la maniero per kiu vi konektas al via servilo per SSH ŝanĝiĝos tiel:",
"user_deletion_failed": "Ne povis forigi uzanton {user}: {error}",
"backup_with_no_backup_script_for_app": "La app '{app:s}' ne havas sekretan skripton. Ignorante.",
"service_regen_conf_is_deprecated": "'yunohost service regen-conf' malakceptas! Bonvolu uzi anstataŭe 'yunohost tools regen-conf'.",
"global_settings_key_doesnt_exists": "La ŝlosilo '{settings_key:s}' ne ekzistas en la tutmondaj agordoj, vi povas vidi ĉiujn disponeblajn klavojn per uzado de 'yunohost settings list'",
"dyndns_no_domain_registered": "Neniu domajno registrita ĉe DynDNS",
"dyndns_could_not_check_available": "Ne povis kontroli ĉu {domain:s} haveblas sur {provider:s}.",
"log_app_removelist": "Forigu aplikan liston",
"global_settings_setting_example_enum": "Ekzemplo enum elekto",
"hook_exec_not_terminated": "Skripto ne finiĝis ĝuste: {path:s}",
"service_stopped": "'{service:s}' servo ĉesis",
"restore_failed": "Ne povis restarigi sistemon",
"confirm_app_install_danger": "Danĝero! Ĉi tiu apliko estas konata ankoraŭ eksperimenta (se ne eksplicite ne funkcias)! Vi probable ne devas instali ĝin krom se vi scias kion vi faras. NENIU SUBTENO estos provizita se ĉi tiu app ne funkcias aŭ rompas vian sistemon ... Se vi pretas riski ĉiuokaze, tajpu '{answers: s}'",
"log_operation_unit_unclosed_properly": "Operaciumo ne estis fermita ĝuste",
"upgrade_complete": "Ĝisdatigo kompleta",
"upnp_enabled": "UPnP ŝaltis",
"mailbox_used_space_dovecot_down": "La retpoŝta servo de Dovecot devas funkcii, se vi volas akcepti uzitan poŝtan spacon",
"restore_system_part_failed": "Ne povis restarigi la sisteman parton '{part:s}'",
"diagnosis_monitor_system_error": "Ne povis monitori sistemon: {error}",
"service_stop_failed": "Ne povis maldaŭrigi la servon '{service:s}'\n\nLastatempaj servaj protokoloj: {logs:s}",
"unbackup_app": "App '{app:s}' ne konserviĝos",
"updating_apt_cache": "Akirante haveblajn ĝisdatigojn por sistemaj pakoj…",
"tools_upgrade_at_least_one": "Bonvolu specifi '--apps' aŭ '--system'",
"service_already_stopped": "La servo '{service:s}' jam ĉesis",
"unit_unknown": "Nekonata unuo '{unit:s}'",
"migration_0003_modified_files": "Bonvolu noti, ke la jenaj dosieroj estis trovitaj mane kaj modifitaj kaj povus esti anstataŭigitaj sekve de la ĝisdatigo: {manual_modified_files}",
"tools_upgrade_cant_both": "Ne eblas ĝisdatigi ambaŭ sistemon kaj programojn samtempe",
"restore_extracting": "Eltirante bezonatajn dosierojn el la ar theivo…",
"upnp_port_open_failed": "Ne povis malfermi havenon per UPnP",
"log_app_upgrade": "Ĝisdatigu la aplikon '{}'",
"log_help_to_get_failed_log": "La operacio '{desc}' ne povis finiĝi. Bonvolu dividi la plenan ŝtipon de ĉi tiu operacio per la komando 'yunohost log display {name} --share' por akiri helpon",
"migration_description_0002_migrate_to_tsig_sha256": "Plibonigu sekurecon de DynDNS TSIG-ĝisdatigoj per SHA-512 anstataŭ MD5",
"monitor_disabled": "Servila monitorado nun malŝaltis",
"pattern_port": "Devas esti valida havena numero (t.e. 0-65535)",
"port_already_closed": "Haveno {port:d} estas jam fermita por {ip_version:s} rilatoj",
"hook_name_unknown": "Nekonata hoko-nomo '{name:s}'",
"migration_0003_system_not_fully_up_to_date": "Via sistemo ne estas plene ĝisdata. Bonvolu plenumi regulan ĝisdatigon antaŭ ol ruli la migradon al Stretch.",
"dyndns_could_not_check_provide": "Ne povis kontroli ĉu {provider:s} povas provizi {domain:s}.",
"dyndns_cron_remove_failed": "Ne povis forigi la cron-laboron DynDNS ĉar: {error}",
"pattern_listname": "Devas esti nur alfanumeraj kaj substrekaj signoj",
"restore_nothings_done": "Nenio estis restarigita",
"log_tools_postinstall": "Afiŝu vian servilon YunoHost",
"dyndns_unavailable": "La domajno '{domain:s}' 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.",
"root_password_replaced_by_admin_password": "Via radika pasvorto estis anstataŭigita per via administra pasvorto.",
"ssowat_persistent_conf_read_error": "Ne povis legi konstantan SSOwat-agordon: {error:s}. Redakti /etc/ssowat/conf.json.persistent dosiero por ripari la Jaks-sintakson",
"migration_description_0005_postgresql_9p4_to_9p6": "Migru datumbazojn de PostgreSQL 9.4 al 9.6",
"migration_0008_root": "• Vi ne povos konekti kiel radiko per SSH. Anstataŭe vi uzu la administran uzanton;",
"package_unknown": "Nekonata pako '{pkgname}'",
"domain_unknown": "Nekonata domajno",
"global_settings_setting_security_password_user_strength": "Uzanto pasvorta forto",
"restore_may_be_not_enough_disk_space": "Via sistemo ŝajnas ne havi sufiĉe da spaco (free:{free_space:d} B, necesa spaco: {needed_space:d} B, sekureca marĝeno: {margin:d} B)",
"log_corrupted_md_file": "La YAD-metadata dosiero asociita kun protokoloj estas damaĝita: '{md_file}\nEraro: {error} '",
"downloading": "Elŝutante …",
"user_deleted": "Uzanto forigita",
"service_enable_failed": "Ne eblis ŝalti la servon '{service:s}'\n\nLastatempaj servaj protokoloj: {logs:s}",
"tools_upgrade_special_packages": "Nun ĝisdatigi 'specialajn' (rilatajn al yunohost)…",
"domains_available": "Haveblaj domajnoj:",
"dyndns_registered": "Registrita domajno DynDNS",
"service_description_fail2ban": "Protektas kontraŭ bruta forto kaj aliaj specoj de atakoj de la interreto",
"file_does_not_exist": "La dosiero {path:s} ne ekzistas.",
"yunohost_not_installed": "YunoHost estas malĝuste aŭ ne ĝuste instalita. Bonvolu prilabori 'yunohost tools postinstall'",
"migration_0005_postgresql_96_not_installed": "PostgreSQL 9.4 estas instalita, sed ne postgresql 9.6‽ Io stranga eble okazis en via sistemo: (…",
"restore_removing_tmp_dir_failed": "Ne povis forigi malnovan provizoran dosierujon",
"certmanager_cannot_read_cert": "Io malbona okazis, kiam mi provis malfermi aktualan atestilon por domajno {domain:s} (dosiero: {file:s}), kialo: {reason:s}",
"service_removed": "'{service:s}' servo forigita",
"certmanager_hit_rate_limit": "Tro multaj atestiloj jam eldonitaj por ĉi tiu ĝusta aro de domajnoj {domain:s} antaŭ nelonge. Bonvolu reprovi poste. Vidu https://letsencrypt.org/docs/rate-limits/ por pliaj detaloj",
"migration_0005_not_enough_space": "Disponigu sufiĉan spacon en {path} por ruli la migradon.",
"pattern_firstname": "Devas esti valida antaŭnomo",
"migration_description_0010_migrate_to_apps_json": "Forigu malvalorigitajn aparatojn kaj uzu anstataŭe la novan unuigitan liston \"apps.json\"",
"domain_cert_gen_failed": "Ne povis generi atestilon",
"regenconf_file_kept_back": "La agorda dosiero '{conf}' estas atendita forigi per regen-conf (kategorio {category}), sed ĝi estis konservita.",
"migrate_tsig_wait_4": "30 sekundoj …",
"backup_with_no_restore_script_for_app": "La apliko \"{app:s}\" ne havas restarigan skripton, vi ne povos aŭtomate restarigi la sekurkopion de ĉi tiu apliko.",
"log_letsencrypt_cert_install": "Instalu atestilon Let's Encrypt sur '{}' regado",
"log_dyndns_update": "Ĝisdatigu la IP asociita kun via subdominio YunoHost '{}'",
"firewall_reload_failed": "Ne eblis reŝargi la firewall",
"confirm_app_install_warning": "Averto: Ĉi tiu aplikaĵo povas funkcii, sed ne bone integras en YunoHost. Iuj funkcioj kiel ekzemple aliĝilo kaj sekurkopio / restarigo eble ne haveblos. Instali ĉiuokaze? [{answers: s}] ",
"log_user_delete": "Forigi uzanton '{}'",
"dyndns_ip_updated": "Ĝisdatigis vian IP sur DynDNS",
"regenconf_up_to_date": "La agordo jam estas ĝisdatigita por kategorio '{category}'",
"migration_0003_patching_sources_list": "Patching the sources.lists …",
"global_settings_setting_security_ssh_compatibility": "Kongruo vs sekureca kompromiso por la SSH-servilo. Afektas la ĉifradojn (kaj aliajn aspektojn pri sekureco)",
"migrations_need_to_accept_disclaimer": "Por funkciigi la migradon {id}, via devas akcepti la sekvan malakcepton:\n---\n{malavantaĝo}\n---\nSe vi akceptas funkcii la migradon, bonvolu rekonduki la komandon kun la opcio '--accept-disclaimer'.",
"regenconf_file_remove_failed": "Ne povis forigi la agordodosieron '{conf}'",
"not_enough_disk_space": "Ne sufiĉe libera spaco sur '{path:s}'",
"migration_0006_disclaimer": "YunoHost nun atendas, ke la pasvortoj de admin kaj radiko estos sinkronigitaj. Ĉi tiu migrado anstataŭigas vian radikan pasvorton kun la administran pasvorton.",
"dyndns_ip_update_failed": "Ne povis ĝisdatigi IP-adreson al DynDNS",
"migration_description_0004_php5_to_php7_pools": "Rekonfigu la PHP-naĝejojn por uzi PHP 7 anstataŭ 5",
"monitor_glances_con_failed": "Ne povis konektiĝi al servilo de Glances",
"ssowat_conf_updated": "SSOwat-agordo ĝisdatigita",
"log_link_to_failed_log": "Ne povis plenumi la operacion '{desc}'. Bonvolu provizi la plenan protokolon de ĉi tiu operacio per <a href=\"#/tools/logs/{name}\"> alklakante ĉi tie </a> por akiri helpon",
"log_app_fetchlist": "Aldonu liston de aplikoj",
"user_home_creation_failed": "Ne povis krei dosierujon \"home\" por uzanto",
"pattern_backup_archive_name": "Devas esti valida dosiernomo kun maksimume 30 signoj, alfanombraj kaj -_. signoj nur",
"restore_cleaning_failed": "Ne eblis purigi la adresaron de provizora restarigo",
"dyndns_registration_failed": "Ne povis registri DynDNS-domajnon: {error:s}",
"migration_0003_not_jessie": "La nuna Debian-distribuo ne estas Jessie!",
"user_unknown": "Nekonata uzanto: {user:s}",
"migrations_to_be_ran_manually": "Migrado {id} devas funkcii permane. Bonvolu iri al Iloj → Migradoj en la retpaĝa paĝo, aŭ kuri `yunohost tools migrations migrate`.",
"migration_0008_warning": "Se vi komprenas tiujn avertojn kaj konsentas lasi YunoHost pretervidi vian nunan agordon, faru la migradon. Alie, vi ankaŭ povas salti la migradon - kvankam ĝi ne rekomendas.",
"certmanager_cert_renew_success": "Ni Ĉifru atestilon renovigitan por la domajno '{domain:s}'",
"global_settings_reset_success": "Antaŭaj agordoj nun estas rezervitaj al {path:s}",
"pattern_domain": "Devas esti valida domajna nomo (t.e. mia-domino.org)",
"package_unexpected_error": "Neatendita eraro okazis prilaborante la pakon '{pkgname}'",
"dyndns_key_generating": "Generi DNS-ŝlosilon ... Eble daŭros iom da tempo.",
"restore_running_app_script": "Restarigi la programon '{app:s}'…",
"migrations_skip_migration": "Salti migradon {id}…",
"mysql_db_init_failed": "MysQL-datumbazo init malsukcesis",
"regenconf_file_removed": "Agordodosiero '{conf}' forigita",
"log_tools_shutdown": "Enŝaltu vian servilon",
"password_too_simple_3": "La pasvorto bezonas almenaŭ 8 signojn kaj enhavas ciferon, majusklon, pli malaltan kaj specialajn signojn",
"migration_0003_general_warning": "Bonvolu noti, ke ĉi tiu migrado estas delikata operacio. La teamo de YunoHost faris sian plej bonan revizii kaj testi ĝin, sed la migrado eble ankoraŭ rompos partojn de la sistemo aŭ ĝiaj programoj.\n\nTial oni rekomendas al:\n - Elfari kopion de iuj kritikaj datumoj aŭ app. Pliaj informoj pri https://yunohost.org/backup;\n - Paciencu post lanĉo de la migrado: Depende de via interreta konekto kaj aparataro, eble daŭros kelkaj horoj ĝis ĉio ĝisdatigi.\n\nAldone, la haveno por SMTP, uzata de eksteraj retpoŝtaj klientoj (kiel Thunderbird aŭ K9-Mail) estis ŝanĝita de 465 (SSL / TLS) al 587 (STARTTLS). La malnova haveno (465) aŭtomate fermiĝos, kaj la nova haveno (587) malfermiĝos en la fajrejo. Vi kaj viaj uzantoj * devos adapti la agordon de viaj retpoŝtaj klientoj laŭe.",
"diagnosis_kernel_version_error": "Ne povis akiri la kernan version: {error}",
"global_settings_setting_example_int": "Ekzemple int elekto",
"backup_output_symlink_dir_broken": "Via arkiva dosierujo '{path:s}' estas rompita ligilo. Eble vi forgesis restarigi aŭ munti aŭ enŝovi la stokadon, al kiu ĝi notas.",
"good_practices_about_admin_password": "Vi nun estas por difini novan administran pasvorton. La pasvorto devas esti almenaŭ 8 signoj - kvankam estas bone praktiki uzi pli longan pasvorton (t.e. pasfrazon) kaj / aŭ uzi variaĵon de signoj (majuskloj, minuskloj, ciferoj kaj specialaj signoj).",
"certmanager_attempt_to_renew_valid_cert": "La atestilo por la domajno '{domain:s}' ne finiĝos! (Vi eble uzos --force se vi scias kion vi faras)",
"restore_running_hooks": "Kurantaj restarigaj hokoj…",
"regenconf_pending_applying": "Aplikante pritraktata agordo por kategorio '{category}'…",
"service_description_dovecot": "Permesas al retpoŝtaj klientoj aliri / serĉi retpoŝton (per IMAP kaj POP3)",
"domain_dns_conf_is_just_a_recommendation": "Ĉi tiu komando montras al vi la *rekomenditan* agordon. Ĝi efektive ne agordas la DNS-agordon por vi. Via respondeco agordi vian DNS-zonon en via registristo laŭ ĉi tiu rekomendo.",
"backup_php5_to_php7_migration_may_fail": "Ne povis konverti vian ar archiveivon por subteni PHP 7, vi eble ne povas restarigi viajn PHP-programojn (kialo: {error:s})",
"log_backup_restore_system": "Restarigi sistemon de rezerva arkivo",
"log_app_change_url": "Ŝanĝu la URL de la apliko '{}'",
"service_already_started": "La servo '{service:s}' estas jam komencita",
"license_undefined": "nedifinita",
"global_settings_setting_security_password_admin_strength": "Admin pasvorta forto",
"service_reload_or_restart_failed": "Ne povis reŝargi aŭ rekomenci la servon '{service:s}'\n\nLastatempaj servaj protokoloj: {logs:s}",
"migrations_list_conflict_pending_done": "Vi ne povas uzi ambaŭ '--previous' kaj '--done' samtempe.",
"maindomain_changed": "La ĉefa domajno nun ŝanĝiĝis",
"server_shutdown_confirm": "La servilo haltos tuj, ĉu vi certas? [{answers:s}]",
"monitor_period_invalid": "Nevalida tempoperiodo",
"log_backup_restore_app": "Restarigu '{}' de rezerva ar archiveivo",
"log_does_exists": "Ne estas operacio-registro kun la nomo '{log}', uzu 'yunohost loglist' por vidi ĉiujn disponeblajn operaciojn",
"service_add_failed": "Ne povis aldoni la servon '{service:s}'",
"pattern_password_app": "Bedaŭrinde, pasvortoj ne povas enhavi jenajn signojn: {forbidden_chars}",
"this_action_broke_dpkg": "Ĉi tiu ago rompis dpkg / APT (la administrantoj pri la paka sistemo) ... Vi povas provi solvi ĉi tiun problemon per konekto per SSH kaj funkcianta `sudo dpkg --configure -a`.",
"log_regen_conf": "Regeneri sistemajn agordojn '{}'",
"restore_hook_unavailable": "La restariga skripto por '{part:s}' ne haveblas en via sistemo kaj ankaŭ ne en la ar theivo",
"network_check_smtp_ok": "Eksteren retpoŝto (SMTP-haveno 25) ne estas blokita",
"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",
"migration_0003_main_upgrade": "Komencanta ĉefa ĝisdatigo …",
"user_info_failed": "Ne povis akiri informojn pri uzanto",
"regenconf_file_updated": "Agordodosiero '{conf}' ĝisdatigita",
"log_help_to_get_log": "Por vidi la protokolon de la operacio '{desc}', uzu la komandon 'yunohost log display {name}'",
"global_settings_setting_security_nginx_compatibility": "Kongruo vs sekureca kompromiso por la TTT-servilo NGINX. Afektas la ĉifradojn (kaj aliajn aspektojn pri sekureco)",
"no_internet_connection": "Servilo ne konektita al la interreto",
"migration_0008_dsa": "• La DSA-ŝlosilo estos malŝaltita. Tial vi eble bezonos nuligi spuran averton de via SSH-kliento kaj revizii la fingrospuron de via servilo;",
"migration_0003_restoring_origin_nginx_conf": "Fileia dosiero /etc/nginx/nginx.conf estis iel redaktita. La migrado reaperos unue al sia originala stato ... La antaŭa dosiero estos havebla kiel {backup_dest}.",
"migrate_tsig_end": "Migrado al HMAC-SHA-512 finiĝis",
"restore_complete": "Restarigita",
"certmanager_couldnt_fetch_intermediate_cert": "Ekvilibrigita kiam vi provis ricevi interajn atestilojn de Let's Encrypt. Atestita instalado / renovigo nuligita - bonvolu reprovi poste.",
"hook_exec_failed": "Ne povis funkcii skripto: {path:s}",
"global_settings_cant_open_settings": "Ne eblis malfermi agordojn, tial: {reason:s}",
"user_created": "Uzanto kreita",
"service_description_avahi-daemon": "Permesas al vi atingi vian servilon uzante 'yunohost.local' en via loka reto",
"certmanager_attempt_to_replace_valid_cert": "Vi provas anstataŭigi bonan kaj validan atestilon por domajno {domajno:s}! (Uzu --forte pretervidi)",
"monitor_stats_period_unavailable": "Ne ekzistas disponeblaj statistikoj por la periodo",
"regenconf_updated": "Agordo por kategorio '{category}' ĝisdatigita",
"update_apt_cache_warning": "Io iris malbone dum la ĝisdatigo de la kaŝmemoro de APT (paka administranto de Debian). Jen rubujo de la sources.list-linioj, kiuj povus helpi identigi problemajn liniojn:\n{sourcelist}",
"regenconf_dry_pending_applying": "Kontrolado de pritraktata agordo, kiu estus aplikita por kategorio '{category}'…",
"regenconf_file_copy_failed": "Ne povis kopii la novan agordodosieron '{new}' al '{conf}'",
"global_settings_setting_example_string": "Ekzemple korda elekto",
"restore_already_installed_app": "App kun la ID '{app:s}' estas jam instalita",
"mountpoint_unknown": "Nekonata montpunkto",
"log_tools_maindomain": "Faru de '{}' la ĉefa domajno",
"maindomain_change_failed": "Ne povis ŝanĝi la ĉefan domajnon",
"mail_domain_unknown": "Nevalida retadreso por domajno '{domain:s}'. Bonvolu uzi domajnon administritan de ĉi tiu servilo.",
"migrations_cant_reach_migration_file": "Ne povis aliri migrajn dosierojn ĉe la vojo% s",
"pattern_email": "Devas esti valida retpoŝtadreso (t.e.iu@domain.org)",
"mail_alias_remove_failed": "Ne povis forigi retpoŝton alias '{mail:s}'",
"regenconf_file_manually_removed": "La dosiero de agordo '{conf}' estis forigita permane, kaj ne estos kreita",
"monitor_enabled": "Servila monitorado nun ŝaltis",
"domain_exists": "La domajno jam ekzistas",
"migration_description_0001_change_cert_group_to_sslcert": "Ŝanĝu grupajn permesojn de 'metronomo' al 'ssl-cert'",
"mysql_db_creation_failed": "MySQL-datumbazkreado malsukcesis",
"ldap_initialized": "LDAP inicializis",
"migrate_tsig_not_needed": "Vi ne ŝajnas uzi DynDNS-domajnon, do neniu migrado necesas.",
"certmanager_domain_cert_not_selfsigned": "La atestilo por domajno {domajno:s} ne estas mem-subskribita. Ĉu vi certas, ke vi volas anstataŭigi ĝin? (Uzu '--force' por fari tion.)",
"certmanager_unable_to_parse_self_CA_name": "Ne povis trapasi nomon de mem-subskribinta aŭtoritato (dosiero: {file: s})",
"log_selfsigned_cert_install": "Instalu mem-subskribitan atestilon sur '{}' domajno",
"log_tools_reboot": "Reklamu vian servilon",
"certmanager_cert_install_success": "Ni Ĉifru atestilon nun instalitan por la domajno '{domain:s}'",
"global_settings_bad_choice_for_enum": "Malbona elekto por agordo {setting:s}, ricevita '{choice:s}', sed disponeblaj elektoj estas: {available_choices:s}",
"server_shutdown": "La servilo haltos",
"log_tools_migrations_migrate_forward": "Migri antaŭen",
"migration_0008_no_warning": "Neniu grava risko identigita pri superregado de via SSH-agordo, tamen oni ne povas esti absolute certa;)! Ekfunkciu la migradon por superregi ĝin. Alie, vi ankaŭ povas salti la migradon - kvankam ĝi ne rekomendas.",
"regenconf_now_managed_by_yunohost": "La agorda dosiero '{conf}' nun estas administrata de YunoHost (kategorio {category}).",
"server_reboot_confirm": "Ĉu la servilo rekomencos tuj, ĉu vi certas? [{answers:s}]",
"log_app_install": "Instalu la aplikon '{}'",
"service_description_dnsmasq": "Traktas rezolucion de domajna nomo (DNS)",
"global_settings_unknown_type": "Neatendita situacio, la agordo {setting:s} ŝajnas havi la tipon {unknown_type:s} sed ĝi ne estas tipo subtenata de la sistemo.",
"migration_0003_problematic_apps_warning": "Bonvolu noti, ke la sekvaj eventuale problemaj instalitaj apps estis detektitaj. Ĝi aspektas, ke tiuj ne estis instalitaj de aparato aŭ ne estas markitaj kiel \"funkciantaj\". Tial ne eblas garantii, ke ili ankoraŭ funkcios post la ĝisdatigo: {problematic_apps}",
"domain_hostname_failed": "Ne povis agordi novan gastigilon. Ĉi tio eble kaŭzos problemon poste (eble bone).",
"server_reboot": "La servilo rekomenciĝos",
"regenconf_failed": "Ne povis regeneri la agordon por kategorio(j): {categories}",
"domain_uninstall_app_first": "Unu aŭ pluraj programoj estas instalitaj en ĉi tiu domajno. Bonvolu malinstali ilin antaŭ ol daŭrigi la domajnan forigon",
"port_unavailable": "Haveno {port:d} ne haveblas",
"service_unknown": "Nekonata servo '{service:s}'",
"migration_0003_start": "Komencante migradon al Stretch. La protokoloj haveblos en {logfile}.",
"monitor_stats_no_update": "Neniuj monitoradaj statistikoj ĝisdatigi",
"domain_deletion_failed": "Ne povis forigi domajnon {domain}: {error}",
"log_user_update": "Ĝisdatigu uzantinformojn de '{}'",
"user_creation_failed": "Ne povis krei uzanton {user}: {error}",
"migrations_migration_has_failed": "Migrado {id} ne kompletigis, abolis. Eraro: {exception}",
"done": "Farita",
"log_domain_remove": "Forigi domon '{}' de agordo de sistemo",
"monitor_not_enabled": "Servila monitorado estas malŝaltita",
"diagnosis_debian_version_error": "Ne povis retrovi la Debianan version: {error}",
"hook_list_by_invalid": "Ĉi tiu posedaĵo ne povas esti uzata por listigi hokojn",
"confirm_app_install_thirdparty": "Danĝero! Ĉi tiu apliko ne estas parto de la aplika katalogo de Yunohost. Instali triajn aplikojn povas kompromiti la integrecon kaj sekurecon de via sistemo. Vi probable ne devas instali ĝin krom se vi scias kion vi faras. NENIU SUBTENO estos provizita se ĉi tiu app ne funkcias aŭ rompas vian sistemon ... Se vi pretas riski ĉiuokaze, tajpu '{answers: s}'",
"global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Permesu uzon de (malaktuala) DSA-hostkey por la agordo de daemon SSH",
"dyndns_domain_not_provided": "Provizanto DynDNS {provider:s} ne povas provizi domajnon {domain:s}.",
"backup_unable_to_organize_files": "Ne povis uzi la rapidan metodon por organizi dosierojn en la ar archiveivo",
"password_too_simple_2": "La pasvorto bezonas almenaŭ 8 signojn kaj enhavas ciferon, majusklojn kaj minusklojn",
"executing_script": "Plenumanta skripto '{script:s}' …",
"service_cmd_exec_failed": "Ne povis plenumi la komandon '{command:s}'",
"migration_0007_cancelled": "Ne povis plibonigi la manieron kiel via SSH-agordo estas administrita.",
"migrate_tsig_failed": "Ne povis migri la DynDNS-domajnon '{domain}' al HMAC-SHA-512, ruliĝante. Eraro: {error_code}, {error}",
"pattern_lastname": "Devas esti valida familinomo",
"service_enabled": "'{service:s}' servo malŝaltita",
"certmanager_no_cert_file": "Ne povis legi la atestan dosieron por la domajno {domain:s} (dosiero: {file:s})",
"migration_0008_port": "• Vi devos konekti uzante la havenon 22 anstataŭ via nuna kutimo SSH-haveno. Sentu vin libera reconfiguri ĝin;",
"domain_creation_failed": "Ne povis krei domajnon {domain}: {error}",
"certmanager_domain_http_not_working": "Ŝajnas ke la domajno {domain:s} ne atingeblas per HTTP. Kontrolu, ke via DNS kaj NGINX-agordo ĝustas",
"domain_cannot_remove_main": "Ne eblas forigi ĉefan domajnon. Fiksu unu unue",
"service_reloaded_or_restarted": "'{service:s}' servo reŝarĝis aŭ rekomencis",
"mysql_db_initialized": "La datumbazo MySQL jam estas pravalorizita",
"log_domain_add": "Aldonu '{}' domajnon en sisteman agordon",
"global_settings_bad_type_for_setting": "Malbona tipo por agordo {setting:s}, ricevita {received_type:s}, atendata {expected_type:s}",
"unlimit": "Neniu kvoto",
"dyndns_cron_installed": "Kreita laboro DynDNS cron",
"system_username_exists": "Uzantnomo jam ekzistas en la listo de uzantoj de sistemo",
"firewall_reloaded": "Fajroŝirmilo reŝarĝis",
"service_restarted": "'{service:s}' servo rekomencis",
"pattern_username": "Devas esti minuskulaj literoj kaj minuskloj nur",
"extracting": "Eltirante…",
"restore_app_failed": "Ne povis restarigi la programon '{app:s}'",
"yunohost_configured": "YunoHost nun agordis",
"certmanager_self_ca_conf_file_not_found": "Ne povis trovi agorddosieron por mem-subskriba aŭtoritato (dosiero: {file:s})",
"log_app_remove": "Forigu la aplikon '{}'",
"service_restart_failed": "Ne povis rekomenci la servon '{service:s}'\n\nLastatempaj servaj protokoloj: {logs:s}",
"firewall_rules_cmd_failed": "Iuj komandoj pri fajroŝirmilo malsukcesis. Pliaj informoj en ensaluto.",
"certmanager_certificate_fetching_or_enabling_failed": "Provante uzi la novan atestilon por {domain:s} ne funkciis …",
"app_full_domain_unavailable": "Bedaŭrinde, ĉi tiu app devas esti instalita sur propra domajno, sed aliaj programoj jam estas instalitaj sur la domajno '{domain}'. Vi povus uzi subdominon dediĉitan al ĉi tiu app anstataŭe.",
"migration_0011_slapd_config_will_be_overwritten": "Ŝajnas ke vi permane redaktis la slapd-agordon. Por ĉi tiu kritika migrado, YunoHost bezonas devigi la ĝisdatigon de la slapd-agordo. La originalaj dosieroj estos rezervitaj en {conf_backup_folder}.",
"group_cannot_edit_all_users": "La grupo 'all_users' ne povas esti redaktita permane. Ĝi estas speciala grupo celita enhavi ĉiujn uzantojn registritajn en YunoHost",
"group_cannot_edit_visitors": "La grupo 'vizitantoj' ne povas esti redaktita permane. Ĝi estas speciala grupo reprezentanta anonimajn vizitantojn",
"group_cannot_edit_primary_group": "La grupo '{group}' ne povas esti redaktita permane. Ĝi estas la primara grupo celita enhavi nur unu specifan uzanton.",
"log_permission_url": "Ĝisdatigu url-rilataj al permeso '{}'",
"permission_already_up_to_date": "La permeso ne estis ĝisdatigita ĉar la petoj pri aldono/forigo jam kongruas kun la aktuala stato.",
"permission_currently_allowed_for_visitors": "Ĉi tiu permeso estas nuntempe donita al vizitantoj aldone al aliaj grupoj. Vi probable volas aŭ forigi la permeson de \"vizitantoj\" aŭ forigi la aliajn grupojn al kiuj ĝi nun estas koncedita.",
"permission_currently_allowed_for_all_users": "Ĉi tiu permeso estas nuntempe donita al ĉiuj uzantoj aldone al aliaj grupoj. Vi probable volas aŭ forigi la permeson \"all_users\" aŭ forigi la aliajn grupojn, kiujn ĝi nuntempe donas.",
"app_install_failed": "Ne povis instali {app} : {error}",
"app_install_script_failed": "Eraro okazis en la skripto de instalado de la app"
}

View file

@ -2,37 +2,37 @@
"action_invalid": "Acción no válida '{action:s} 1'",
"admin_password": "Contraseña administrativa",
"admin_password_change_failed": "No se puede cambiar la contraseña",
"admin_password_changed": "La contraseña administrativa ha sido cambiada",
"app_already_installed": "{app:s} 2 ya está instalada",
"app_argument_choice_invalid": "Opción no válida para el argumento '{name:s} 3', deber una de {choices:s} 4",
"app_argument_invalid": "Valor no válido para el argumento '{name:s} 5': {error:s} 6",
"admin_password_changed": "La contraseña de administración ha sido cambiada",
"app_already_installed": "{app:s} ya está instalada",
"app_argument_choice_invalid": "Use una de estas opciones «{choices:s}» para el argumento «{name:s}»",
"app_argument_invalid": "Elija un valor válido para el argumento «{name:s}»: {error:s}",
"app_argument_required": "Se requiere el argumento '{name:s} 7'",
"app_extraction_failed": "No se pudieron extraer los archivos de instalación",
"app_id_invalid": "Id de la aplicación no válida",
"app_id_invalid": "ID de la aplicación no válida",
"app_incompatible": "La aplicación {app} no es compatible con su versión de YunoHost",
"app_install_files_invalid": "Los archivos de instalación no son válidos",
"app_location_already_used": "La aplicación {app} ya está instalada en esta localización ({path})",
"app_location_install_failed": "No se puede instalar la aplicación en esta localización porque entra en conflicto con la aplicación '{other_app}' ya instalada en '{other_path}'",
"app_manifest_invalid": "El manifiesto de la aplicación no es válido: {error}",
"app_no_upgrade": "No hay aplicaciones para actualizar",
"app_install_files_invalid": "Estos archivos no se pueden instalar",
"app_location_already_used": "La aplicación «{app}» ya está instalada en ({path})",
"app_location_install_failed": "No se puede instalar la aplicación ahí porque entra en conflicto con la aplicación «{other_app}» ya instalada en «{other_path}»",
"app_manifest_invalid": "Algo va mal con el manifiesto de la aplicación: {error}",
"app_no_upgrade": "Todas las aplicaciones están ya actualizadas",
"app_not_correctly_installed": "La aplicación {app:s} 8 parece estar incorrectamente instalada",
"app_not_installed": "La aplicación «{app:s}» no está instalada. Esta es la lista de todas las aplicaciones instaladas: {all_apps}",
"app_not_installed": "No se pudo encontrar la aplicación «{app:s}» en la lista de aplicaciones instaladas: {all_apps}",
"app_not_properly_removed": "La {app:s} 0 no ha sido desinstalada correctamente",
"app_package_need_update": "El paquete de la aplicación {app} necesita ser actualizada debido a los cambios en YunoHost",
"app_recent_version_required": "{:s} requiere una versión más reciente de moulinette ",
"app_removed": "{app:s} ha sido eliminada",
"app_removed": "Eliminado {app:s}",
"app_requirements_checking": "Comprobando los paquetes necesarios para {app}…",
"app_requirements_failed": "No se cumplen los requisitos para {app}: {error}",
"app_requirements_failed": "No se cumplen algunos requisitos para {app}: {error}",
"app_requirements_unmeet": "No se cumplen los requisitos para {app}, el paquete {pkgname} ({version}) debe ser {spec}",
"app_sources_fetch_failed": "No se pudo obtener los archivos con el código fuente, ¿es la URL correcta?",
"app_sources_fetch_failed": "No se pudieron obtener los archivos con el código fuente, ¿es el URL correcto?",
"app_unknown": "Aplicación desconocida",
"app_unsupported_remote_type": "Tipo remoto no soportado por la aplicación",
"app_upgrade_failed": "No se pudo actualizar la aplicación {app:s}",
"app_upgraded": "{app:s} ha sido actualizada",
"appslist_fetched": "La lista de aplicaciones {appslist:s} ha sido descargada",
"appslist_removed": "La lista de aplicaciones {appslist:s} ha sido eliminada",
"appslist_retrieve_error": "No se pudo recuperar la lista remota de aplicaciones {appslist:s} : {error:s}",
"appslist_unknown": "Lista de aplicaciones {appslist:s} desconocida.",
"app_upgrade_failed": "No se pudo actualizar {app:s}",
"app_upgraded": "Actualizado {app:s}",
"appslist_fetched": "Lista de aplicaciones «{appslist:s}» actualizada",
"appslist_removed": "Eliminada la lista de aplicaciones «{appslist:s}»",
"appslist_retrieve_error": "No se puede recuperar la lista remota de aplicaciones «{appslist:s}»: {error:s}",
"appslist_unknown": "Lista de aplicaciones «{appslist:s}» desconocida.",
"ask_current_admin_password": "Contraseña administrativa actual",
"ask_email": "Dirección de correo electrónico",
"ask_firstname": "Nombre",
@ -42,43 +42,43 @@
"ask_new_admin_password": "Nueva contraseña administrativa",
"ask_password": "Contraseña",
"backup_action_required": "Debe especificar algo que guardar",
"backup_app_failed": "No es posible realizar la copia de seguridad de la aplicación '{app:s}'",
"backup_archive_app_not_found": "La aplicación '{app:s}' no ha sido encontrada en la copia de seguridad",
"backup_app_failed": "No se pudo respaldar la aplicación «{app:s}»",
"backup_archive_app_not_found": "No se pudo encontrar la aplicación «{app:s}» en el archivo de respaldo",
"backup_archive_hook_not_exec": "El hook {hook:s} no ha sido ejecutado en esta copia de seguridad",
"backup_archive_name_exists": "Ya existe una copia de seguridad con ese nombre",
"backup_archive_name_exists": "Ya existe un archivo de respaldo con este nombre.",
"backup_archive_name_unknown": "Copia de seguridad local desconocida '{name:s}'",
"backup_archive_open_failed": "No se pudo abrir la copia de seguridad",
"backup_cleaning_failed": "No se puede limpiar el directorio temporal de copias de seguridad",
"backup_archive_open_failed": "No se pudo abrir el archivo de respaldo",
"backup_cleaning_failed": "No se pudo limpiar la carpeta de respaldo temporal",
"backup_created": "Se ha creado la copia de seguridad",
"backup_creating_archive": "Creando el archivo de copia de seguridad…",
"backup_creation_failed": "No se pudo crear la copia de seguridad",
"backup_delete_error": "No se puede eliminar '{path:s}'",
"backup_deleted": "La copia de seguridad ha sido eliminada",
"backup_extracting_archive": "Extrayendo el archivo de la copia de seguridad…",
"backup_hook_unknown": "Hook de copia de seguridad desconocido '{hook:s}'",
"backup_invalid_archive": "La copia de seguridad no es válida",
"backup_nothings_done": "No hay nada que guardar",
"backup_output_directory_forbidden": "Directorio de salida no permitido. Las copias de seguridad no pueden ser creadas en /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var o en los subdirectorios de /home/yunohost.backup/archives",
"backup_output_directory_not_empty": "El directorio de salida no está vacío",
"backup_creation_failed": "No se pudo crear el archivo de respaldo",
"backup_delete_error": "No se pudo eliminar «{path:s}»",
"backup_deleted": "Eliminada la copia de seguridad",
"backup_extracting_archive": "Extrayendo el archivo de respaldo…",
"backup_hook_unknown": "El gancho «{hook:s}» de la copia de seguridad es desconocido",
"backup_invalid_archive": "Esto no es un archivo de respaldo",
"backup_nothings_done": "Nada que guardar",
"backup_output_directory_forbidden": "Elija un directorio de salida diferente. No se pueden crear copias de seguridad en las subcarpetas de /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var o /home/yunohost.backup/archives",
"backup_output_directory_not_empty": "Debe elegir un directorio de salida vacío",
"backup_output_directory_required": "Debe proporcionar un directorio de salida para la copia de seguridad",
"backup_running_app_script": "Ejecutando la script de copia de seguridad de la aplicación '{app:s}'...",
"backup_running_hooks": "Ejecutando los hooks de copia de seguridad...",
"custom_app_url_required": "Debe proporcionar una URL para actualizar su aplicación personalizada {app:s}",
"custom_appslist_name_required": "Debe proporcionar un nombre para su lista de aplicaciones personalizadas",
"diagnosis_debian_version_error": "No se puede obtener la versión de Debian: {error}",
"diagnosis_kernel_version_error": "No se puede obtener la versión del kernel: {error}",
"diagnosis_monitor_disk_error": "No se pueden monitorizar los discos: {error}",
"diagnosis_monitor_network_error": "No se puede monitorizar la red: {error}",
"diagnosis_monitor_system_error": "No se puede monitorizar el sistema: {error}",
"diagnosis_no_apps": "Aplicación no instalada",
"dnsmasq_isnt_installed": "Parece que dnsmasq no está instalado, ejecute 'apt-get remove bind9 && apt-get install dnsmasq'",
"domain_cert_gen_failed": "No se pudo crear el certificado",
"domain_created": "El dominio ha sido creado",
"domain_creation_failed": "No se pudo crear el dominio",
"domain_deleted": "El dominio ha sido eliminado",
"domain_deletion_failed": "No se pudo borrar el dominio",
"domain_dyndns_already_subscribed": "Ya está suscrito a un dominio DynDNS",
"domain_dyndns_invalid": "Dominio no válido para usar con DynDNS",
"diagnosis_debian_version_error": "No se pudo obtener la versión de Debian: {error}",
"diagnosis_kernel_version_error": "No se pudo obtener la versión del núcleo: {error}",
"diagnosis_monitor_disk_error": "No se pudieron monitorizar los discos: {error}",
"diagnosis_monitor_network_error": "No se pudo monitorizar la red: {error}",
"diagnosis_monitor_system_error": "No se pudo monitorizar el sistema: {error}",
"diagnosis_no_apps": "No hay tal aplicación instalada",
"dnsmasq_isnt_installed": "Parece que dnsmasq no está instalado, ejecute «apt-get remove bind9 && apt-get install it»",
"domain_cert_gen_failed": "No se pudo generar el certificado",
"domain_created": "Dominio creado",
"domain_creation_failed": "No se pudo crear el dominio {domain}: {error}",
"domain_deleted": "Dominio eliminado",
"domain_deletion_failed": "No se pudo eliminar el dominio {domain}: {error}",
"domain_dyndns_already_subscribed": "Ya se ha suscrito a un dominio de DynDNS",
"domain_dyndns_invalid": "Este dominio no se puede usar con DynDNS",
"domain_dyndns_root_unknown": "Dominio raíz de DynDNS desconocido",
"domain_exists": "El dominio ya existe",
"domain_uninstall_app_first": "Una o más aplicaciones están instaladas en este dominio. Debe desinstalarlas antes de eliminar el dominio",
@ -87,77 +87,77 @@
"domain_zone_not_found": "No se ha encontrado el archivo de zona del DNS para el dominio [:s]",
"done": "Hecho.",
"downloading": "Descargando…",
"dyndns_cron_installed": "La tarea cron para DynDNS ha sido instalada",
"dyndns_cron_remove_failed": "No se pudo eliminar la tarea cron de DynDNS por: {error}",
"dyndns_cron_removed": "La tarea cron DynDNS ha sido eliminada",
"dyndns_ip_update_failed": "No se pudo actualizar la dirección IP en el DynDNS",
"dyndns_ip_updated": "Su dirección IP ha sido actualizada en el DynDNS",
"dyndns_key_generating": "Generando la clave del DNS. Esto podría tardar un rato",
"dyndns_cron_installed": "Creado el trabajo de cron de DynDNS",
"dyndns_cron_remove_failed": "No se pudo eliminar el trabajo de cron de DynDNS por: {error}",
"dyndns_cron_removed": "Eliminado el trabajo de cron de DynDNS",
"dyndns_ip_update_failed": "No se pudo actualizar la dirección IP en DynDNS",
"dyndns_ip_updated": "Actualizada su IP en DynDNS",
"dyndns_key_generating": "Generando la clave del DNS. Esto podría tardar un rato.",
"dyndns_key_not_found": "No se ha encontrado la clave DNS para el dominio",
"dyndns_no_domain_registered": "Ningún dominio ha sido registrado con DynDNS",
"dyndns_registered": "El dominio DynDNS ha sido registrado",
"dyndns_registration_failed": "No se pudo registrar el dominio DynDNS: {error:s}",
"dyndns_unavailable": "El dominio {domain:s} no está disponible.",
"dyndns_no_domain_registered": "Ningún dominio registrado con DynDNS",
"dyndns_registered": "Registrado dominio de DynDNS",
"dyndns_registration_failed": "No se pudo registrar el dominio de DynDNS: {error:s}",
"dyndns_unavailable": "El dominio «{domain:s}» no está disponible.",
"executing_command": "Ejecutando la orden «{command:s}»…",
"executing_script": "Ejecutando el guión «{script:s}»…",
"extracting": "Extrayendo…",
"field_invalid": "Campo no válido '{:s}'",
"firewall_reload_failed": "No se pudo recargar el cortafuegos",
"firewall_reloaded": "El cortafuegos ha sido recargado",
"firewall_rules_cmd_failed": "No se pudieron aplicar algunas reglas del cortafuegos. Para más información consulte el registro.",
"firewall_reloaded": "Cortafuegos recargado",
"firewall_rules_cmd_failed": "Algunas órdenes de las reglas del cortafuegos han fallado. Más información en el registro.",
"format_datetime_short": "%d/%m/%Y %I:%M %p",
"hook_argument_missing": "Falta un parámetro '{:s}'",
"hook_choice_invalid": "Selección inválida '{:s}'",
"hook_exec_failed": "No se puede ejecutar el script: {path:s}",
"hook_exec_not_terminated": "La ejecución del script no ha terminado: {path:s}",
"hook_list_by_invalid": "Enumerar los hooks por validez",
"hook_exec_failed": "No se pudo ejecutar el guión: {path:s}",
"hook_exec_not_terminated": "El guión no terminó correctamente:{path:s}",
"hook_list_by_invalid": "Esta propiedad no se puede usar para enumerar ganchos («hooks»)",
"hook_name_unknown": "Nombre de hook desconocido '{name:s}'",
"installation_complete": "Instalación finalizada",
"installation_failed": "No se pudo realizar la instalación",
"installation_failed": "Algo ha ido mal con la instalación",
"ip6tables_unavailable": "No puede modificar ip6tables aquí. O bien está en un 'container' o su kernel no soporta esta opción",
"iptables_unavailable": "No puede modificar iptables aquí. O bien está en un 'container' o su kernel no soporta esta opción",
"ldap_initialized": "Se ha inicializado LDAP",
"ldap_initialized": "Inicializado LDAP",
"license_undefined": "indefinido",
"mail_alias_remove_failed": "No se pudo eliminar el alias de correo '{mail:s}'",
"mail_domain_unknown": "El dominio de correo '{domain:s}' es desconocido",
"mail_forward_remove_failed": "No se pudo eliminar el reenvío de correo '{mail:s}'",
"mail_alias_remove_failed": "No se pudo eliminar el alias de correo «{mail:s}»",
"mail_domain_unknown": "Dirección de correo no válida para el dominio «{domain:s}». Use un dominio administrado por este servidor.",
"mail_forward_remove_failed": "No se pudo eliminar el reenvío de correo «{mail:s}»",
"maindomain_change_failed": "No se pudo cambiar el dominio principal",
"maindomain_changed": "Se ha cambiado el dominio principal",
"monitor_disabled": "La monitorización del sistema ha sido deshabilitada",
"monitor_enabled": "La monitorización del sistema ha sido habilitada",
"monitor_glances_con_failed": "No se pudo conectar al servidor Glances",
"monitor_not_enabled": "La monitorización del sistema no está habilitada",
"maindomain_changed": "El dominio principal ha cambiado",
"monitor_disabled": "La monitorización del servidor está ahora desactivada",
"monitor_enabled": "La monitorización del servidor está ahora activada",
"monitor_glances_con_failed": "No se pudo conectar al servidor de Glances",
"monitor_not_enabled": "La monitorización del servidor está apagada",
"monitor_period_invalid": "Período de tiempo no válido",
"monitor_stats_file_not_found": "No se pudo encontrar el archivo de estadísticas",
"monitor_stats_no_update": "No hay estadísticas de monitorización para actualizar",
"monitor_stats_period_unavailable": "No hay estadísticas para el período",
"mountpoint_unknown": "Punto de montaje desconocido",
"mysql_db_creation_failed": "No se pudo crear la base de datos MySQL",
"mysql_db_init_failed": "No se pudo iniciar la base de datos MySQL",
"mysql_db_initialized": "La base de datos MySQL ha sido inicializada",
"mysql_db_init_failed": "No se pudo inicializar la base de datos MySQL",
"mysql_db_initialized": "La base de datos MySQL está ahora inicializada",
"network_check_mx_ko": "El registro DNS MX no está configurado",
"network_check_smtp_ko": "El puerto 25 (SMTP) para el correo saliente parece estar bloqueado por su red",
"network_check_smtp_ok": "El puerto de salida del correo electrónico (25, SMTP) no está bloqueado",
"network_check_smtp_ko": "El correo saliente (SMTP puerto 25) parece estar bloqueado por su red",
"network_check_smtp_ok": "El correo saliente (SMTP puerto 25) no está bloqueado",
"new_domain_required": "Debe proporcionar el nuevo dominio principal",
"no_appslist_found": "No se ha encontrado ninguna lista de aplicaciones",
"no_internet_connection": "El servidor no está conectado a Internet",
"no_ipv6_connectivity": "La conexión por IPv6 no está disponible",
"no_restore_script": "No se ha encontrado un script de restauración para la aplicación '{app:s}'",
"not_enough_disk_space": "No hay suficiente espacio en '{path:s}'",
"package_not_installed": "El paquete '{pkgname}' no está instalado",
"not_enough_disk_space": "No hay espacio libre suficiente en «{path:s}»",
"package_not_installed": "El paquete «{pkgname}» no está instalado",
"package_unexpected_error": "Ha ocurrido un error inesperado procesando el paquete '{pkgname}'",
"package_unknown": "Paquete desconocido '{pkgname}'",
"packages_no_upgrade": "No hay paquetes para actualizar",
"packages_upgrade_critical_later": "Los paquetes críticos ({packages:s}) serán actualizados más tarde",
"packages_upgrade_failed": "No se pudieron actualizar todos los paquetes",
"path_removal_failed": "No se pudo eliminar la ruta {:s}",
"pattern_backup_archive_name": "Debe ser un nombre de archivo válido con un máximo de 30 caracteres, solo se admiten caracteres alfanuméricos, los guiones -_ y el punto",
"pattern_backup_archive_name": "Debe ser un nombre de archivo válido con un máximo de 30 caracteres, solo se admiten caracteres alfanuméricos y los caracteres -_. (guiones y punto)",
"pattern_domain": "El nombre de dominio debe ser válido (por ejemplo mi-dominio.org)",
"pattern_email": "Debe ser una dirección de correo electrónico válida (por ejemplo, alguien@dominio.org)",
"pattern_email": "Debe ser una dirección de correo electrónico válida (p.ej. alguien@example.com)",
"pattern_firstname": "Debe ser un nombre válido",
"pattern_lastname": "Debe ser un apellido válido",
"pattern_listname": "Solo se pueden usar caracteres alfanuméricos y el guion bajo",
"pattern_mailbox_quota": "El tamaño de cuota debe tener uno de los sufijos b/k/M/G/T. Usar 0 para cuota ilimitada",
"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_port": "Debe ser un número de puerto válido (es decir, entre 0-65535)",
"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)",
@ -167,22 +167,22 @@
"port_already_opened": "El puerto {port:d} ya está abierto para las conexiones {ip_version:s}",
"port_available": "El puerto {port:d} está disponible",
"port_unavailable": "El puerto {port:d} no está disponible",
"restore_action_required": "Debe especificar algo que restaurar",
"restore_already_installed_app": "Una aplicación con la id '{app:s}' ya está instalada",
"restore_app_failed": "No se puede restaurar la aplicación '{app:s}'",
"restore_cleaning_failed": "No se puede limpiar el directorio temporal de restauración",
"restore_complete": "Restauración finalizada",
"restore_action_required": "Debe escoger algo que restaurar",
"restore_already_installed_app": "Una aplicación con el ID «{app:s}» ya está instalada",
"restore_app_failed": "No se pudo restaurar la aplicación «{app:s}»",
"restore_cleaning_failed": "No se pudo limpiar el directorio temporal de restauración",
"restore_complete": "Restaurada",
"restore_confirm_yunohost_installed": "¿Realmente desea restaurar un sistema ya instalado? [{answers:s}]",
"restore_failed": "No se pudo restaurar el sistema",
"restore_hook_unavailable": "El script de restauración '{part:s}' no está disponible en su sistema y tampoco en el archivo",
"restore_hook_unavailable": "El guión de restauración para «{part:s}» no está disponible en su sistema y tampoco en el archivo",
"restore_nothings_done": "No se ha restaurado nada",
"restore_running_app_script": "Ejecutando el guión de restauración de la aplicación «{app:s}»…",
"restore_running_app_script": "Restaurando la aplicación «{app:s}»…",
"restore_running_hooks": "Ejecutando los ganchos de restauración…",
"service_add_failed": "No se pudo añadir el servicio '{service:s}'",
"service_added": "Servicio '{service:s}' ha sido añadido",
"service_already_started": "El servicio '{service:s}' ya ha sido inicializado",
"service_already_stopped": "El servicio '{service:s}' ya ha sido detenido",
"service_cmd_exec_failed": "No se pudo ejecutar el comando '{command:s}'",
"service_add_failed": "No se pudo añadir el servicio «{service:s}»",
"service_added": "Añadido el servicio «{service:s}»",
"service_already_started": "El servicio «{service:s}» ya está funcionando",
"service_already_stopped": "El servicio «{service:s}» ya ha sido detenido",
"service_cmd_exec_failed": "No se pudo ejecutar la orden «{command:s}»",
"service_conf_file_backed_up": "Se ha realizado una copia de seguridad del archivo de configuración '{conf}' en '{backup}'",
"service_conf_file_copy_failed": "No se puede copiar el nuevo archivo de configuración '{new}' a {conf}",
"service_conf_file_manually_modified": "El archivo de configuración '{conf}' ha sido modificado manualmente y no será actualizado",
@ -194,28 +194,28 @@
"service_conf_up_to_date": "La configuración del servicio '{service}' ya está actualizada",
"service_conf_updated": "La configuración ha sido actualizada para el servicio '{service}'",
"service_conf_would_be_updated": "La configuración podría haber sido actualizada para el servicio '{service} 1'",
"service_disable_failed": "No se pudo deshabilitar el servicio '{service:s}'",
"service_disabled": "El servicio '{service:s}' ha sido deshabilitado",
"service_enable_failed": "No se pudo habilitar el servicio '{service:s}'",
"service_enabled": "El servicio '{service:s}' ha sido habilitado",
"service_no_log": "No hay ningún registro para el servicio '{service:s}'",
"service_disable_failed": "No se pudo desactivar el servicio «{service:s}»\n\nRegistro de servicios recientes:{logs:s}",
"service_disabled": "El servicio «{service:s}» ha sido desactivado",
"service_enable_failed": "No se pudo activar el servicio «{service:s}»\n\nRegistro de servicios recientes:{logs:s}",
"service_enabled": "El servicio «{service:s}» ha sido desactivado",
"service_no_log": "No hay ningún registro que mostrar para el servicio «{service:s}»",
"service_regenconf_dry_pending_applying": "Comprobando configuración pendiente que podría haber sido aplicada al servicio '{service}'...",
"service_regenconf_failed": "No se puede regenerar la configuración para el servicio(s): {services}",
"service_regenconf_pending_applying": "Aplicando la configuración pendiente para el servicio '{service}'...",
"service_remove_failed": "No se pudo desinstalar el servicio '{service:s}'",
"service_removed": "El servicio '{service:s}' ha sido desinstalado",
"service_start_failed": "No se pudo iniciar el servicio '{service:s}'\n\nRegistros de servicio recientes : {logs:s}",
"service_started": "El servicio '{service:s}' ha sido iniciado",
"service_status_failed": "No se pudo determinar el estado del servicio '{service:s}'",
"service_stop_failed": "No se pudo detener el servicio '{service:s}'",
"service_stopped": "El servicio '{service:s}' ha sido detenido",
"service_remove_failed": "No se pudo eliminar el servicio «{service:s}»",
"service_removed": "Eliminado el servicio «{service:s}»",
"service_start_failed": "No se pudo iniciar el servicio «{service:s}»\n\nRegistro de servicios recientes:{logs:s}",
"service_started": "Iniciado el servicio «{service:s}»",
"service_status_failed": "No se pudo determinar el estado del servicio «{service:s}»",
"service_stop_failed": "No se pudo detener el servicio «{service:s}»\n\nRegistro de servicios recientes:{logs:s}",
"service_stopped": "El servicio «{service:s}» se detuvo",
"service_unknown": "Servicio desconocido '{service:s}'",
"ssowat_conf_generated": "Se ha generado la configuración de SSOwat",
"ssowat_conf_updated": "La configuración de SSOwat ha sido actualizada",
"system_upgraded": "El sistema ha sido actualizado",
"system_username_exists": "El nombre de usuario ya existe en el sistema",
"ssowat_conf_generated": "Generada la configuración de SSOwat",
"ssowat_conf_updated": "Actualizada la configuración de SSOwat",
"system_upgraded": "Sistema actualizado",
"system_username_exists": "El nombre de usuario ya existe en la lista de usuarios del sistema",
"unbackup_app": "La aplicación '{app:s}' no se guardará",
"unexpected_error": "Ha ocurrido un error inesperado",
"unexpected_error": "Algo inesperado salió mal: {error}",
"unit_unknown": "Unidad desconocida '{unit:s}'",
"unlimit": "Sin cuota",
"unrestore_app": "La aplicación '{app:s}' no será restaurada",
@ -224,290 +224,290 @@
"upgrade_complete": "Actualización finalizada",
"upgrading_packages": "Actualizando paquetes…",
"upnp_dev_not_found": "No se encontró ningún dispositivo UPnP",
"upnp_disabled": "UPnP ha sido deshabilitado",
"upnp_enabled": "UPnP ha sido habilitado",
"upnp_port_open_failed": "No se pudieron abrir puertos por UPnP",
"user_created": "El usuario ha sido creado",
"user_creation_failed": "No se pudo crear el usuario",
"user_deleted": "El usuario ha sido eliminado",
"user_deletion_failed": "No se pudo eliminar el usuario",
"user_home_creation_failed": "No se puede crear el directorio de usuario 'home'",
"user_info_failed": "No se pudo extraer la información del usuario",
"upnp_disabled": "UPnP desactivado",
"upnp_enabled": "UPnP activado",
"upnp_port_open_failed": "No se pudo abrir el puerto vía UPnP",
"user_created": "Usuario creado",
"user_creation_failed": "No se pudo crear el usuario {user}: {error}",
"user_deleted": "Usuario eliminado",
"user_deletion_failed": "No se pudo eliminar el usuario {user}: {error}",
"user_home_creation_failed": "No se pudo crear la carpeta «home» para el usuario",
"user_info_failed": "No se pudo obtener la información del usuario",
"user_unknown": "Usuario desconocido: {user:s}",
"user_update_failed": "No se pudo actualizar el usuario",
"user_updated": "El usuario ha sido actualizado",
"user_update_failed": "No se pudo actualizar el usuario {user}: {error}",
"user_updated": "Cambiada la información de usuario",
"yunohost_already_installed": "YunoHost ya está instalado",
"yunohost_ca_creation_failed": "No se pudo crear el certificado de autoridad",
"yunohost_configured": "YunoHost ha sido configurado",
"yunohost_ca_creation_failed": "No se pudo crear la autoridad de certificación",
"yunohost_configured": "YunoHost está ahora configurado",
"yunohost_installing": "Instalando YunoHost…",
"yunohost_not_installed": "YunoHost no está instalado o ha habido errores en la instalación. Ejecute 'yunohost tools postinstall'",
"ldap_init_failed_to_create_admin": "La inicialización de LDAP falló al crear el usuario administrador",
"mailbox_used_space_dovecot_down": "El servicio de e-mail Dovecot debe estar funcionando si desea obtener el espacio utilizado por el buzón de correo",
"ssowat_persistent_conf_read_error": "Error al leer la configuración persistente de SSOwat: {error:s}. Edite el archivo /etc/ssowat/conf.json.persistent para corregir la sintaxis de JSON",
"ssowat_persistent_conf_write_error": "Error al guardar la configuración persistente de SSOwat: {error:s}. Edite el archivo /etc/ssowat/conf.json.persistent para corregir la sintaxis de JSON",
"yunohost_not_installed": "YunoHost no está correctamente instalado. Ejecute «yunohost tools postinstall»",
"ldap_init_failed_to_create_admin": "La inicialización de LDAP no pudo crear el usuario «admin»",
"mailbox_used_space_dovecot_down": "El servicio de correo Dovecot debe estar funcionando si desea obtener el espacio usado por el buzón de correo",
"ssowat_persistent_conf_read_error": "No se pudo leer la configuración persistente de SSOwat: {error:s}. Edite el archivo /etc/ssowat/conf.json.persistent para corregir la sintaxis de JSON",
"ssowat_persistent_conf_write_error": "No se pudo guardar la configuración persistente de SSOwat: {error:s}. Edite el archivo /etc/ssowat/conf.json.persistent para corregir la sintaxis de JSON",
"certmanager_attempt_to_replace_valid_cert": "Está intentando sobrescribir un certificado correcto y válido para el dominio {domain:s}! (Use --force para omitir este mensaje)",
"certmanager_domain_unknown": "Dominio desconocido {domain:s}",
"certmanager_domain_cert_not_selfsigned": "El certificado para el dominio {domain:s} no es un certificado autofirmado. ¿Está seguro de que quiere reemplazarlo? (Use --force para omitir este mensaje)",
"certmanager_certificate_fetching_or_enabling_failed": "Suena como que habilitar el nuevo certificado para {domain:s} fallara de algún modo…",
"certmanager_attempt_to_renew_nonLE_cert": "El certificado para el dominio {domain:s} no ha sido emitido por Let's Encrypt. ¡No se puede renovar automáticamente!",
"certmanager_attempt_to_renew_valid_cert": "¡El certificado para el dominio {domain:s} no está a punto de expirar! (Puede usar --force si sabe lo que está haciendo)",
"certmanager_domain_http_not_working": "Parece que no se puede acceder al dominio {domain:s} a través de HTTP. Compruebe que la configuración del DNS y de nginx es correcta",
"certmanager_error_no_A_record": "No se ha encontrado un registro DNS 'A' para el dominio {domain:s}. Debe hacer que su nombre de dominio apunte a su máquina para poder instalar un certificado Let's Encrypt. (Si sabe lo que está haciendo, use --no-checks para desactivar esas comprobaciones.)",
"certmanager_domain_dns_ip_differs_from_public_ip": "El registro DNS 'A' para el dominio {domain:s} es diferente de la IP de este servidor. Si recientemente modificó su registro A, espere a que se propague (existen algunos controladores de propagación DNS disponibles en línea). (Si sabe lo que está haciendo, use --no-checks para desactivar esas comprobaciones.)",
"certmanager_domain_unknown": "Dominio desconocido «{domain:s}»",
"certmanager_domain_cert_not_selfsigned": "El certificado para el dominio {domain:s} no es un certificado autofirmado. ¿Está seguro de que quiere reemplazarlo? (Use «--force» para hacerlo)",
"certmanager_certificate_fetching_or_enabling_failed": "El intento de usar el nuevo certificado para {domain:s} no ha funcionado…",
"certmanager_attempt_to_renew_nonLE_cert": "El certificado para el dominio «{domain:s}» no ha sido emitido por Let's Encrypt. ¡No se puede renovar automáticamente!",
"certmanager_attempt_to_renew_valid_cert": "¡El certificado para el dominio «{domain:s}» no está a punto de expirar! (Puede usar --force si sabe lo que está haciendo)",
"certmanager_domain_http_not_working": "Parece que no se puede acceder al dominio {domain:s} a través de HTTP. Compruebe que la configuración del DNS y de NGINX es correcta",
"certmanager_error_no_A_record": "No se ha encontrado un registro DNS «A» para el dominio {domain:s}. Debe hacer que su nombre de dominio apunte a su máquina para poder instalar un certificado de Let's Encrypt. (Si sabe lo que está haciendo, use «--no-checks» para desactivar esas comprobaciones.)",
"certmanager_domain_dns_ip_differs_from_public_ip": "El registro «A» del DNS para el dominio «{domain:s}» es diferente de la IP de este servidor. Si recientemente modificó su registro A, espere a que se propague (existen algunos verificadores de propagación de DNS disponibles en línea). (Si sabe lo que está haciendo, use «--no-checks» para desactivar esas comprobaciones.)",
"certmanager_cannot_read_cert": "Se ha producido un error al intentar abrir el certificado actual para el dominio {domain:s} (archivo: {file:s}), razón: {reason:s}",
"certmanager_cert_install_success_selfsigned": "¡Se ha instalado correctamente un certificado autofirmado para el dominio {domain:s}!",
"certmanager_cert_install_success": "¡Se ha instalado correctamente un certificado Let's Encrypt para el dominio {domain:s}!",
"certmanager_cert_renew_success": "¡Se ha renovado correctamente el certificado Let's Encrypt para el dominio {domain:s}!",
"certmanager_cert_install_success_selfsigned": "Instalado correctamente un certificado autofirmado para el dominio «{domain:s}»",
"certmanager_cert_install_success": "Instalado correctamente un certificado de Let's Encrypt para el dominio «{domain:s}»",
"certmanager_cert_renew_success": "Renovado correctamente el certificado de Let's Encrypt para el dominio «{domain:s}»",
"certmanager_old_letsencrypt_app_detected": "\nYunohost ha detectado que la aplicación 'letsencrypt' está instalada, esto produce conflictos con las nuevas funciones de administración de certificados integradas en Yunohost. Si desea utilizar las nuevas funciones integradas, ejecute los siguientes comandos para migrar su instalación:\n\n Yunohost app remove letsencrypt\n Yunohost domain cert-install\n\nP.D.: esto intentará reinstalar los certificados para todos los dominios con un certificado Let's Encrypt o con un certificado autofirmado",
"certmanager_hit_rate_limit": "Se han emitido demasiados certificados recientemente para el conjunto de dominios {domain:s}. Por favor, inténtelo de nuevo más tarde. Consulte https://letsencrypt.org/docs/rate-limits/ para obtener más detalles",
"certmanager_hit_rate_limit": "Se han emitido demasiados certificados recientemente para este conjunto exacto de dominios {domain:s}. Pruebe de nuevo más tarde. Vea para más detalles https://letsencrypt.org/docs/rate-limits/",
"certmanager_cert_signing_failed": "No se pudo firmar el nuevo certificado",
"certmanager_no_cert_file": "No se puede leer el certificado para el dominio {domain:s} (archivo: {file:s})",
"certmanager_conflicting_nginx_file": "No se puede preparar el dominio para el desafío ACME: el archivo de configuración nginx {filepath:s} está en conflicto y debe ser eliminado primero",
"domain_cannot_remove_main": "No se puede eliminar el dominio principal. Primero debe establecer un nuevo dominio principal",
"certmanager_self_ca_conf_file_not_found": "No se ha encontrado el archivo de configuración para la autoridad de autofirma (file: {file:s})",
"certmanager_unable_to_parse_self_CA_name": "No se puede procesar el nombre de la autoridad de autofirma (file: {file:s} 1)",
"certmanager_no_cert_file": "No se pudo leer el certificado para el dominio {domain:s} (archivo: {file:s})",
"certmanager_conflicting_nginx_file": "No se pudo preparar el dominio para el desafío ACME: el archivo de configuración de NGINX {filepath:s} está en conflicto y debe ser eliminado primero",
"domain_cannot_remove_main": "No se puede eliminar el dominio principal. Configure uno primero",
"certmanager_self_ca_conf_file_not_found": "No se pudo encontrar el archivo de configuración para la autoridad de autofirma (archivo: {file:s})",
"certmanager_unable_to_parse_self_CA_name": "No se pudo procesar el nombre de la autoridad de autofirma (archivo: {file:s})",
"domains_available": "Dominios disponibles:",
"backup_archive_broken_link": "Imposible acceder a la copia de seguridad (enlace roto {path:s})",
"certmanager_domain_not_resolved_locally": "Su servidor Yunohost no consigue resolver el dominio {domain:s}. Esto puede suceder si ha modificado su registro DNS. Si es el caso, espere unas horas hasta que se propague la modificación. Si el problema persiste, considere añadir {domain:s} a /etc/hosts. (Si sabe lo que está haciendo, use --no-checks para deshabilitar estas verificaciones.)",
"certmanager_acme_not_configured_for_domain": "El certificado para el dominio {domain:s} no parece instalado correctamente. Ejecute primero cert-install para este dominio.",
"certmanager_http_check_timeout": "Plazo expirado, el servidor no ha podido contactarse a si mismo a través de HTTP usando su dirección IP pública (dominio {domain:s} con ip {ip:s}). Puede ser debido a hairpinning o a una mala configuración del cortafuego/router al que está conectado su servidor.",
"certmanager_couldnt_fetch_intermediate_cert": "Plazo expirado, no se ha podido descargar el certificado intermedio de Let's Encrypt. La instalación/renovación del certificado ha sido cancelada - vuelva a intentarlo más tarde.",
"appslist_retrieve_bad_format": "El archivo obtenido para la lista de aplicaciones {appslist:s} no es válido",
"domain_hostname_failed": "Error al establecer un nuevo nombre de host («hostname»). Esto podría causar problemas más tarde (no es seguro... podría ir bien).",
"yunohost_ca_creation_success": "Se ha creado la autoridad de certificación local.",
"app_already_installed_cant_change_url": "Esta aplicación ya está instalada. No se puede cambiar el URL únicamente mediante esta función. Compruebe si está disponible la opción 'app changeurl'.",
"backup_archive_broken_link": "No se pudo acceder al archivo de respaldo (enlace roto a {path:s})",
"certmanager_domain_not_resolved_locally": "El dominio {domain:s} no puede ser resuelto desde su servidor de YunoHost. Esto puede suceder si ha modificado su registro DNS recientemente. De ser así, espere unas horas para que se propague. Si el problema continúa, considere añadir {domain:s} a /etc/hosts. (Si sabe lo que está haciendo, use «--no-checks» para desactivar esas comprobaciones.)",
"certmanager_acme_not_configured_for_domain": "El certificado para el dominio «{domain:s}» no parece que esté instalado correctamente. Ejecute primero «cert-install» para este dominio.",
"certmanager_http_check_timeout": "Tiempo de espera agotado cuando el servidor intentaba conectarse consigo mismo a través de HTTP usando una dirección IP pública (dominio «{domain:s}» con IP «{ip:s}»). Puede que esté experimentando un problema de redirección («hairpinning»), o que el cortafuegos o el enrutador de su servidor esté mal configurado.",
"certmanager_couldnt_fetch_intermediate_cert": "Tiempo de espera agotado intentando obtener el certificado intermedio de Let's Encrypt. Cancelada la instalación o renovación del certificado. Vuelva a intentarlo más tarde.",
"appslist_retrieve_bad_format": "No se pudo leer la lista de aplicaciones obtenida «{appslist:s}»",
"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).",
"yunohost_ca_creation_success": "Creada la autoridad de certificación local.",
"app_already_installed_cant_change_url": "Esta aplicación ya está instalada. No se puede cambiar el URL únicamente mediante esta función. Compruebe si está disponible la opción `app changeurl`.",
"app_change_no_change_url_script": "La aplicacion {app_name:s} aún no permite cambiar su URL, es posible que deba actualizarla.",
"app_change_url_failed_nginx_reload": "No se pudo recargar nginx. Compruebe la salida de 'nginx -t':\n{nginx_errors:s}",
"app_change_url_failed_nginx_reload": "No se pudo recargar NGINX. Esta es la salida de «nginx -t»:\n{nginx_errors:s}",
"app_change_url_identical_domains": "El antiguo y nuevo dominio/url_path son idénticos ('{domain:s} {path:s}'), no se realizarán cambios.",
"app_change_url_no_script": "Esta aplicación '{app_name:s}' aún no permite modificar su URL. Quizás debería actualizar la aplicación.",
"app_change_url_success": "El URL de la aplicación {app:s} ha sido cambiado correctamente a {domain:s} {path:s}",
"app_location_unavailable": "Este URL no está disponible o está en conflicto con otra aplicación instalada:\n{apps:s}",
"app_change_url_no_script": "La aplicación «{app_name:s}» 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:s} es ahora {domain:s} {path:s}",
"app_location_unavailable": "Este URL o no está disponible o está en conflicto con otra(s) aplicación(es) instalada(s):\n{apps:s}",
"app_already_up_to_date": "La aplicación {app:s} ya está actualizada",
"appslist_name_already_tracked": "Ya existe una lista de aplicaciones registrada con el nombre {name:s}.",
"appslist_url_already_tracked": "Ya existe una lista de aplicaciones registrada con el URL {url:s}.",
"appslist_migrating": "Migrando la lista de aplicaciones {appslist:s}…",
"appslist_could_not_migrate": "No se pudo migrar la lista de aplicaciones {appslist:s}! No se pudo analizar el URL ... El antiguo cronjob se ha mantenido en {bkp_file:s}.",
"appslist_name_already_tracked": "Ya existe una lista de aplicaciones registradas con el nombre {name:s}.",
"appslist_url_already_tracked": "Ya existe una lista de aplicaciones registradas con el URL {url:s}.",
"appslist_migrating": "Migrando la lista de aplicaciones «{appslist:s}»…",
"appslist_could_not_migrate": "¡No se pudo migrar la lista de aplicaciones «{appslist:s}»! No se pudo analizar el URL… El antiguo trabajo de cron se mantuvo en {bkp_file:s}.",
"appslist_corrupted_json": "No se pudieron cargar las listas de aplicaciones. Parece que {filename:s} está dañado.",
"invalid_url_format": "Formato de URL no válido",
"invalid_url_format": "Algo va mal con el URL",
"app_upgrade_some_app_failed": "No se pudieron actualizar algunas aplicaciones",
"app_make_default_location_already_used": "No puede hacer la aplicación '{app}' por defecto en el dominio {domain} dado que está siendo usado por otra aplicación '{other_app}'",
"app_upgrade_app_name": "Actualizando la aplicación {app}…",
"app_make_default_location_already_used": "No puede hacer que la aplicación «{app}» sea la predeterminada en el dominio, «{domain}» ya está siendo usado por otra aplicación «{other_app}»",
"app_upgrade_app_name": "Actualizando ahora {app}…",
"ask_path": "Camino",
"backup_abstract_method": "Este método de backup no ha sido implementado aún",
"backup_abstract_method": "Este método de respaldo aún no se ha implementado",
"backup_applying_method_borg": "Enviando todos los archivos para la copia de seguridad al repositorio de borg-backup…",
"backup_applying_method_copy": "Copiando todos los archivos a la copia de seguridad…",
"backup_applying_method_custom": "Llamando al método de copia de seguridad personalizado «{method:s}»…",
"backup_applying_method_tar": "Creando el archivo tar de la copia de seguridad…",
"backup_archive_mount_failed": "Fallo en el montado del archivo de backup",
"backup_archive_system_part_not_available": "La parte del sistema {part:s} no está disponible en este backup",
"backup_archive_writing_error": "No se pueden añadir archivos de backup en el archivo comprimido",
"backup_ask_for_copying_if_needed": "Algunos ficheros no pudieron ser preparados para hacer backup usando el método que evita el gasto de espacio temporal en el sistema. Para hacer el backup, {size:s} MB deberían ser usados temporalmente. ¿Está de acuerdo?",
"backup_borg_not_implemented": "Método de backup Borg no está implementado aún",
"backup_cant_mount_uncompress_archive": "No se puede montar en modo solo lectura el directorio del archivo descomprimido",
"backup_applying_method_tar": "Creando el archivo TAR de respaldo…",
"backup_archive_mount_failed": "No se pudo montar el archivo de respaldo",
"backup_archive_system_part_not_available": "La parte del sistema «{part:s}» no está disponible en esta copia de seguridad",
"backup_archive_writing_error": "No se pudieron añadir los archivos «{source:s}» (llamados en el archivo «{dest:s}») para ser respaldados en el archivo comprimido «{archive:s}»",
"backup_ask_for_copying_if_needed": "¿Quiere realizar la copia de seguridad usando {size:s} MB temporalmente? (Se usa este modo ya que algunos archivos no se pudieron preparar usando un método más eficiente.)",
"backup_borg_not_implemented": "El método de respaldo de Borg aún no ha sido implementado",
"backup_cant_mount_uncompress_archive": "No se pudo montar el archivo descomprimido como protegido contra escritura",
"backup_copying_to_organize_the_archive": "Copiando {size:s}MB para organizar el archivo",
"backup_couldnt_bind": "No puede enlazar {src:s} con {dest:s}.",
"backup_csv_addition_failed": "No puede añadir archivos al backup en el archivo CSV",
"backup_csv_creation_failed": "No se puede crear el archivo CSV necesario para futuras operaciones de restauración",
"backup_custom_mount_error": "Fracaso del método de copia de seguridad personalizada en la etapa \"mount\"",
"backup_custom_need_mount_error": "Fracaso del método de copia de seguridad personalizada en la étapa \"need_mount\"",
"backup_no_uncompress_archive_dir": "El directorio del archivo descomprimido no existe",
"backup_php5_to_php7_migration_may_fail": "No se ha podido convertir su archivo para soportar php7, la restauración de sus aplicaciones php puede fallar (razón : {error:s})",
"backup_system_part_failed": "No se puede hacer una copia de seguridad de la parte \"{part:s}\" del sistema",
"backup_with_no_backup_script_for_app": "La aplicación {app:s} no tiene script de respaldo. Se ha ignorado.",
"backup_with_no_restore_script_for_app": "La aplicación {app:s} no tiene script de restauración, no podrá restaurar automáticamente la copia de seguridad de esta aplicación.",
"backup_couldnt_bind": "No se pudo enlazar {src:s} con {dest:s}.",
"backup_csv_addition_failed": "No se pudo añadir archivos para respaldar en el archivo CSV",
"backup_csv_creation_failed": "No se pudo crear el archivo CSV necesario para la restauración",
"backup_custom_mount_error": "El método de respaldo personalizado no pudo superar el paso «mount»",
"backup_custom_need_mount_error": "El método de respaldo personalizado no pudo superar el paso «need_mount»",
"backup_no_uncompress_archive_dir": "No existe tal directorio de archivos sin comprimir",
"backup_php5_to_php7_migration_may_fail": "No se pudo convertir su archivo para que sea compatible con PHP 7, puede que no pueda restaurar sus aplicaciones de PHP (motivo: {error:s})",
"backup_system_part_failed": "No se pudo respaldar la parte del sistema «{part:s}»",
"backup_with_no_backup_script_for_app": "La aplicación «{app:s}» no tiene un guión de respaldo. Omitiendo.",
"backup_with_no_restore_script_for_app": "La aplicación «{app:s}» no tiene un guión de restauración, no podrá restaurar automáticamente la copia de seguridad de esta aplicación.",
"dyndns_could_not_check_provide": "No se pudo verificar si {provider:s} puede ofrecer {domain:s}.",
"dyndns_domain_not_provided": "El proveedor Dyndns {provider:s} no puede proporcionar el dominio {domain:s}.",
"experimental_feature": "Cuidado : esta funcionalidad es experimental y no es considerada estable, no debería usarla excepto si sabe lo que hace.",
"good_practices_about_user_password": "Está a punto de establecer una nueva contraseña de usuario. La contraseña debería de ser de al menos 8 caracteres, aunque es una buena práctica usar una contraseña más larga (es decir, una frase de paso) y/o usar varias clases de caracteres (mayúsculas, minúsculas, dígitos y caracteres especiales).",
"password_listed": "Esta contraseña es una de las más usadas en el mundo. Elija algo un poco más único.",
"dyndns_domain_not_provided": "El proveedor de DynDNS {provider:s} no puede proporcionar el dominio {domain:s}.",
"experimental_feature": "Aviso : esta funcionalidad es experimental y no se considera estable, no debería usarla a menos que sepa lo que está haciendo.",
"good_practices_about_user_password": "Está a punto de establecer una nueva contraseña de usuario. La contraseña debería de ser de al menos 8 caracteres, aunque es una buena práctica usar una contraseña más extensa (básicamente una frase) y/o usar caracteres de varias clases (mayúsculas, minúsculas, números y caracteres especiales).",
"password_listed": "Esta contraseña es una de las más usadas en el mundo. Elija algo más único.",
"password_too_simple_1": "La contraseña debe tener al menos 8 caracteres de longitud",
"password_too_simple_2": "La contraseña debe tener al menos 8 caracteres de longitud y contiene dígitos, mayúsculas y minúsculas",
"password_too_simple_3": "La contraseña debe tener al menos 8 caracteres de longitud y contiene dígitos, mayúsculas, minúsculas y caracteres especiales",
"password_too_simple_4": "La contraseña debe tener al menos 12 caracteres de longitud y contiene dígitos, mayúsculas, minúsculas y caracteres especiales",
"password_too_simple_2": "La contraseña tiene que ser de al menos 8 caracteres de longitud e incluir un número y caracteres en mayúsculas y minúsculas",
"password_too_simple_3": "La contraseña tiene que ser de al menos 8 caracteres de longitud e incluir un número, mayúsculas, minúsculas y caracteres especiales",
"password_too_simple_4": "La contraseña tiene que ser de al menos 12 caracteres de longitud e incluir un número, mayúsculas, minúsculas y caracteres especiales",
"users_available": "Usuarios disponibles:",
"user_not_in_group": "Usuario {user:s} no está en el grupo {group:s}",
"user_already_in_group": "Usuario {user:} ya está en el grupo {group:s}",
"user_not_in_group": "El usuario «{user:s}» no está en el grupo «{group:s}»",
"user_already_in_group": "El usuario «{user:}» ya está en el grupo «{group:s}»",
"updating_app_lists": "Obteniendo actualizaciones disponibles para las aplicaciones…",
"update_apt_cache_warning": "Ocurrieron algunos errores durante la actualización de la caché de APT (gestor de paquetes de Debian). Aquí tiene un volcado de las líneas de sources.list que podría ayudarle a identificar las líneas problemáticas:\n{sourceslist}",
"update_apt_cache_failed": "No se puede actualizar la caché de APT (gestor de paquetes de Debian). Aquí tiene un volcado de las líneas de sources.list que podría ayudarle a identificar las líneas problemáticas:\n{sourceslist}",
"tools_upgrade_special_packages_completed": "¡Actualización de paquetes de YunoHost completada!\nPulse [Intro] para recuperar la línea de órdenes",
"tools_upgrade_special_packages_explanation": "Esta acción terminará pero la actualización especial real continuará en segundo plano. No inicie ninguna otra acción en su servidor en aproximadamente 10 minutos (dependiendo de la velocidad de su hardware). Una vez que esté hecho, podría tener que volver a iniciar sesión en la administración web. El registro de actualización estará disponible en Herramientas > Registro (en la administración web) o mediante «yunohost log list» (en la línea de órdenes).",
"tools_upgrade_special_packages": "Actualizando ahora paquetes «especiales» (relacionados con YunoHost)...",
"tools_upgrade_regular_packages_failed": "No se pueden actualizar los paquetes: {packages_list}",
"tools_upgrade_regular_packages": "Actualizando ahora paquetes «normales» (no relacionados con YunoHost)...",
"tools_upgrade_cant_unhold_critical_packages": "No se pueden liberar los paquetes críticos...",
"tools_upgrade_cant_hold_critical_packages": "No se pueden retener los paquetes críticos...",
"update_apt_cache_warning": "Algo fue mal durante la actualización de la caché de APT (gestor de paquetes de Debian). Aquí tiene un volcado de las líneas de sources.list que podría ayudarle a identificar las líneas problemáticas:\n{sourceslist}",
"update_apt_cache_failed": "No se pudo actualizar la caché de APT (gestor de paquetes de Debian). Aquí tiene un volcado de las líneas de sources.list que podría ayudarle a identificar las líneas problemáticas:\n{sourceslist}",
"tools_upgrade_special_packages_completed": "Actualización de paquetes de YunoHost completada.\nPulse [Intro] para regresar a la línea de órdenes",
"tools_upgrade_special_packages_explanation": "Esta acción terminará pero la actualización especial real continuará en segundo plano. No inicie ninguna otra acción en su servidor en aproximadamente 10 minutos (dependiendo de la velocidad de su hardware). Una vez hecho, podría tener que volver a iniciar sesión en la administración web. El registro de actualización estará disponible en Herramientas → Registro (en la página de administración web) o mediante «yunohost log list» (desde la línea de órdenes).",
"tools_upgrade_special_packages": "Actualizando ahora paquetes «especiales» (relacionados con YunoHost)",
"tools_upgrade_regular_packages_failed": "No se pudieron actualizar los paquetes: {packages_list}",
"tools_upgrade_regular_packages": "Actualizando ahora paquetes «normales» (no relacionados con YunoHost)",
"tools_upgrade_cant_unhold_critical_packages": "No se pudo liberar los paquetes críticos…",
"tools_upgrade_cant_hold_critical_packages": "No se pudieron retener los paquetes críticos…",
"tools_upgrade_cant_both": "No se puede actualizar el sistema y las aplicaciones al mismo tiempo",
"tools_upgrade_at_least_one": "Especifique --apps O --system",
"tools_update_failed_to_app_fetchlist": "Error al actualizar la lista de aplicaciones de YunoHost porque: {error}",
"this_action_broke_dpkg": "Esta acción rompió dpkg/apt (los gestores de paquetes del sistema)... Puede tratar de solucionar este problema conectando mediante SSH y ejecutando `sudo dpkg --configure -a`.",
"tools_upgrade_at_least_one": "Especifique «--apps», o «--system»",
"tools_update_failed_to_app_fetchlist": "No se pudo actualizar la lista de aplicaciones de YunoHost porque: {error}",
"this_action_broke_dpkg": "Esta acción rompió dpkg/APT(los gestores de paquetes del sistema)… Puede tratar de solucionar este problema conectando mediante SSH y ejecutando `sudo dpkg --configure -a`.",
"system_groupname_exists": "El nombre de grupo ya existe en el grupo del sistema",
"service_reloaded_or_restarted": "El servicio «{service:s}» ha sido recargado o reiniciado",
"service_reload_or_restart_failed": "No se puede recargar o reiniciar el servicio «{service:s}»'\n\nRegistro de servicios reciente:{logs:s}",
"service_restarted": "El servicio «{service:s}» ha sido reiniciado",
"service_restart_failed": "No se puede reiniciar el servicio «{service:s}»'\n\nRegistro de servicios reciente:{logs:s}",
"service_reload_or_restart_failed": "No se pudo recargar o reiniciar el servicio «{service:s}»\n\nRegistro de servicios recientes:{logs:s}",
"service_restarted": "Reiniciado el servicio «{service:s}»",
"service_restart_failed": "No se pudo reiniciar el servicio «{service:s}»\n\nRegistro de servicios recientes:{logs:s}",
"service_reloaded": "El servicio «{service:s}» ha sido recargado",
"service_reload_failed": "No se puede recargar el servicio «{service:s}»'\n\nRegistro de servicios reciente:{logs:s}",
"service_reload_failed": "No se pudo recargar el servicio «{service:s}»\n\nRegistro de servicios recientes:{logs:s}",
"service_regen_conf_is_deprecated": "¡«yunohost service regen-conf» está obsoleto! Use «yunohost tools regen-conf» en su lugar.",
"service_description_yunohost-firewall": "gestiona los puertos de conexiones abiertos y cerrados a los servicios",
"service_description_yunohost-api": "gestiona las interacciones entre la interfaz web de YunoHost y el sistema",
"service_description_ssh": "le permite conectar a su servidor remotamente mediante un terminal (protocolo SSH)",
"service_description_slapd": "almacena usuarios, dominios e información relacionada",
"service_description_rspamd": "filtra correo no deseado y otras características relacionadas con el correo",
"service_description_rmilter": "comprueba varios parámetros en el correo",
"service_description_redis-server": "una base de datos especializada usada para el acceso rápido de datos, cola de tareas y comunicación entre programas",
"service_description_postfix": "usado para enviar y recibir correos",
"service_description_php7.0-fpm": "ejecuta aplicaciones escritas en PHP con nginx",
"service_description_nslcd": "maneja la conexión del intérprete («shell») de usuario de YunoHost",
"service_description_nginx": "sirve o proporciona acceso a todos los sitios web alojados en su servidor",
"service_description_mysql": "almacena los datos de las aplicaciones (base de datos SQL)",
"service_description_metronome": "gestionar las cuentas XMPP de mensajería instantánea",
"service_description_glances": "supervisa la información del sistema en su servidor",
"service_description_fail2ban": "protege contra ataques de fuerza bruta y otra clase de ataques desde Internet",
"service_description_dovecot": "permite al cliente de correo acceder/traer correo (vía IMAP y POP3)",
"service_description_dnsmasq": "maneja la resolución de nombres de dominio (DNS)",
"service_description_avahi-daemon": "permite acceder a su servidor usando yunohost.local en su red local",
"service_description_yunohost-firewall": "Gestiona los puertos de conexiones abiertos y cerrados a los servicios",
"service_description_yunohost-api": "Gestiona las interacciones entre la interfaz web de YunoHost y el sistema",
"service_description_ssh": "Permite conectar a su servidor remotamente mediante un terminal (protocolo SSH)",
"service_description_slapd": "Almacena usuarios, dominios e información relacionada",
"service_description_rspamd": "Filtra correo no deseado y otras características relacionadas con el correo",
"service_description_rmilter": "Comprueba varios parámetros en el correo",
"service_description_redis-server": "Una base de datos especializada usada para el acceso rápido de datos, cola de tareas y comunicación entre programas",
"service_description_postfix": "Usado para enviar y recibir correos",
"service_description_php7.0-fpm": "Ejecuta aplicaciones escritas en PHP con NGINX",
"service_description_nslcd": "Maneja la conexión del intérprete de órdenes («shell») de usuario de YunoHost",
"service_description_nginx": "Sirve o proporciona acceso a todos los sitios web alojados en su servidor",
"service_description_mysql": "Almacena los datos de la aplicación (base de datos SQL)",
"service_description_metronome": "Gestionar las cuentas XMPP de mensajería instantánea",
"service_description_glances": "Supervisa la información del sistema en su servidor",
"service_description_fail2ban": "Protege contra ataques de fuerza bruta y otras clases de ataques desde Internet",
"service_description_dovecot": "Permite a los clientes de correo acceder/obtener correo (vía IMAP y POP3)",
"service_description_dnsmasq": "Maneja la resolución de nombres de dominio (DNS)",
"service_description_avahi-daemon": "Permite acceder a su servidor usando «yunohost.local» en su red local",
"server_reboot_confirm": "El servidor se reiniciará inmediatamente ¿está seguro? [{answers:s}]",
"server_reboot": "El servidor se reiniciará",
"server_shutdown_confirm": "El servidor se apagará inmediatamente ¿está seguro? [{answers:s}]",
"server_shutdown": "El servidor se apagará",
"root_password_replaced_by_admin_password": "Su contraseña de root ha sido sustituida por su contraseña de administración.",
"root_password_desynchronized": "La contraseña de administración ha sido cambiada pero ¡YunoHost no pudo propagar esto en la contraseña de root!",
"restore_system_part_failed": "No se puede restaurar la parte del sistema «{part:s}»",
"restore_removing_tmp_dir_failed": "No se puede eliminar un antiguo directorio temporal",
"restore_not_enough_disk_space": "Insuficiente espacio en disco (espacio libre: {free_space:d} B, espacio necesario: {needed_space:d} B, margen de seguridad: {margin:d} B)",
"root_password_desynchronized": "La contraseña de administración ha sido cambiada pero ¡YunoHost no pudo propagar esto a la contraseña de root!",
"restore_system_part_failed": "No se pudo restaurar la parte del sistema «{part:s}»",
"restore_removing_tmp_dir_failed": "No se pudo eliminar un directorio temporal antiguo",
"restore_not_enough_disk_space": "Espacio insuficiente (espacio: {free_space:d} B, espacio necesario: {needed_space:d} B, margen de seguridad: {margin:d} B)",
"restore_mounting_archive": "Montando archivo en «{path:s}»",
"restore_may_be_not_enough_disk_space": "Parece que su sistema no tiene suficiente espacio de disco libre (espacio libre: {free_space:d} B, espacio necesario: {needed_space:d} B, margen de seguridad: {margin:d} B)",
"restore_may_be_not_enough_disk_space": "Parece que su sistema no tiene suficiente espacio (libre: {free_space:d} B, espacio necesario: {needed_space:d} B, margen de seguridad: {margin:d} B)",
"restore_extracting": "Extrayendo los archivos necesarios para el archivo…",
"regenconf_pending_applying": "Aplicando la configuración pendiente para la categoría «{category}»…",
"regenconf_failed": "No se puede regenerar la configuración para la(s) categoría(s): {categories}",
"regenconf_failed": "No se pudo regenerar la configuración para la(s) categoría(s): {categories}",
"regenconf_dry_pending_applying": "Comprobando la configuración pendiente que habría sido aplicada para la categoría «{category}»…",
"regenconf_would_be_updated": "La configuración habría sido actualizada para la categoría «{category}»",
"regenconf_updated": "Ha sido actualizada la configuración para la categoría «{category}»",
"regenconf_updated": "Actualizada la configuración para la categoría «{category}»",
"regenconf_up_to_date": "Ya está actualizada la configuración para la categoría «{category}»",
"regenconf_now_managed_by_yunohost": "El archivo de configuración «{conf}» está gestionado ahora por YunoHost (categoría {category}).",
"regenconf_file_updated": "El archivo de configuración «{conf}» ha sido actualizado",
"regenconf_file_removed": "El archivo de configuración «{conf}» ha sido eliminado",
"regenconf_file_remove_failed": "No se puede eliminar el archivo de configuración «{conf}»",
"regenconf_file_updated": "Actualizado el archivo de configuración «{conf}»",
"regenconf_file_removed": "Eliminado el archivo de configuración «{conf}»",
"regenconf_file_remove_failed": "No se pudo eliminar el archivo de configuración «{conf}»",
"regenconf_file_manually_removed": "El archivo de configuración «{conf}» ha sido eliminado manualmente y no se creará",
"regenconf_file_manually_modified": "El archivo de configuración «{conf}» ha sido modificado manualmente y no será actualizado",
"regenconf_file_kept_back": "Se espera que el archivo de configuración «{conf}» sea eliminado por regen-conf (categoría {category}) pero ha sido retenido.",
"regenconf_file_copy_failed": "No se puede copiar el nuevo archivo de configuración «{new}» a «{conf}»",
"regenconf_file_backed_up": "El archivo de configuración «{conf}» ha sido respaldado en «{backup}»",
"remove_user_of_group_not_allowed": "No tiene permiso para eliminar al usuario {user:s} en el grupo {group:s}",
"regenconf_file_copy_failed": "No se pudo copiar el nuevo archivo de configuración «{new}» a «{conf}»",
"regenconf_file_backed_up": "Archivo de configuración «{conf}» respaldado en «{backup}»",
"remove_user_of_group_not_allowed": "No tiene permiso para eliminar al usuario «{user:s}» en el grupo «{group:s}»",
"remove_main_permission_not_allowed": "No se permite eliminar el permiso principal",
"recommend_to_add_first_user": "La posinstalación ha terminado pero YunoHost necesita al menos un usuario para funcionar correctamente, debe añadir uno ejecutando «yunohost user create <nombredeusuario>» o usando la interfaz de administración.",
"permission_update_nothing_to_do": "No hay permisos para actualizar",
"permission_updated": "Permiso «{permission:s}» para la aplicación {app:s} actualizado",
"permission_generated": "La base de datos de permisos se ha actualizado",
"permission_update_failed": "Actualización de permiso fallida",
"permission_name_not_valid": "Nombre de permiso «{permission:s}» no válido",
"permission_not_found": "Permiso «{permission:s}» no encontrado para la aplicación {app:s}",
"permission_deletion_failed": "Permiso «{permission:s}» para eliminar la aplicación «{app:s}» fallido",
"permission_deleted": "Eliminado el permiso «{permission:s}» para la aplicación {app:s}",
"permission_creation_failed": "Ha fallado la creación del permiso",
"permission_created": "Creado el permiso «{permission:s}» para la aplicación {app:s}",
"permission_already_exist": "El permiso «{permission:s}» para la aplicación {app:s} ya existe",
"permission_updated": "Actualizado el permiso «{permission:s}»",
"permission_generated": "Actualizada la base de datos de permisos",
"permission_update_failed": "No se pudo actualizar el permiso «{permission}» : {error}",
"permission_name_not_valid": "Elija un nombre de permiso permitido para «{permission:s}",
"permission_not_found": "No se encontró el permiso «{permission:s}»",
"permission_deletion_failed": "No se pudo eliminar el permiso «{permission}»: {error}",
"permission_deleted": "Eliminado el permiso «{permission:s}»",
"permission_creation_failed": "No se pudo crear el permiso «{permission}»: {error}",
"permission_created": "Creado el permiso «{permission:s}»",
"permission_already_exist": "El permiso «{permission}» ya existe",
"permission_already_clear": "El permiso «{permission:s}» ya está definido para la aplicación {app:s}",
"pattern_password_app": "Las contraseñas no deben incluir los siguientes caracteres: {forbidden_chars}",
"need_define_permission_before": "Necesita redefinir los permisos ejecutando «yunohost user permission add -u USUARIO» antes de eliminar un grupo permitido",
"migrations_to_be_ran_manually": "La migración {id} hay que ejecutarla manualmente. Vaya a Herramientas > Migraciones en la web de administración o ejecute `yunohost tools migrations migrate`.",
"migrations_success_forward": "¡Migración {id} ejecutada correctamente!",
"pattern_password_app": "Las contraseñas no pueden incluir los siguientes caracteres: {forbidden_chars}",
"need_define_permission_before": "Redefina los permisos ejecutando «yunohost user permission add -u USUARIO» antes de eliminar un grupo permitido",
"migrations_to_be_ran_manually": "La migración {id} hay que ejecutarla manualmente. Vaya a Herramientas → Migraciones en la página web de administración o ejecute `yunohost tools migrations migrate`.",
"migrations_success_forward": "Migración {id} completada",
"migrations_skip_migration": "Omitiendo migración {id}…",
"migrations_running_forward": "Ejecutando migración {id}…",
"migrations_pending_cant_rerun": "Esas migraciones están aún pendientes así que no se pueden volver a ejecutar: {ids}",
"migrations_not_pending_cant_skip": "Esas migraciones no están pendientes así que no pueden ser omitidas: {ids}",
"migrations_no_such_migration": "No existe una migración llamada {id}",
"migrations_pending_cant_rerun": "Esas migraciones están aún pendientes, así que no se pueden volver a ejecutar: {ids}",
"migrations_not_pending_cant_skip": "Esas migraciones no están pendientes, así que no pueden ser omitidas: {ids}",
"migrations_no_such_migration": "No hay ninguna migración llamada «{id}»",
"migrations_no_migrations_to_run": "No hay migraciones que ejecutar",
"migrations_need_to_accept_disclaimer": "Para ejecutar la migración {id} debe aceptar el siguiente descargo de responsabilidad:\n---\n{disclaimer}\n---\nSi acepta ejecutar la migración, vuelva a ejecutar la orden con la opción --accept-disclaimer.",
"migrations_must_provide_explicit_targets": "Necesita proporcionar objetivos explícitos al usar --skip o --force-rerun",
"migrations_migration_has_failed": "Migración {id} fallida, cancelando. Error: {exception}",
"migrations_need_to_accept_disclaimer": "Para ejecutar la migración {id} debe aceptar el siguiente descargo de responsabilidad:\n---\n{disclaimer}\n---\nSi acepta ejecutar la migración, vuelva a ejecutar la orden con la opción «--accept-disclaimer».",
"migrations_must_provide_explicit_targets": "Necesita proporcionar objetivos explícitos al usar «--skip» or «--force-rerun»",
"migrations_migration_has_failed": "La migración {id} no se ha completado, cancelando. Error: {exception}",
"migrations_loading_migration": "Cargando migración {id}…",
"migrations_list_conflict_pending_done": "No puede usar --previous y --done al mismo tiempo.",
"migrations_exclusive_options": "--auto, --skip, and --force-rerun son opciones excluyentes.",
"migrations_failed_to_load_migration": "Error al cargar la migración {id} : {error}",
"migrations_dependencies_not_satisfied": "No se puede ejecutar la migración {id} porque primero necesita ejecutar estas migraciones: {dependencies_id}",
"migrations_cant_reach_migration_file": "No se pueden acceder los archivos de migración en la ruta %s",
"migrations_already_ran": "Esas migraciones ya se han ejecutado: {ids}",
"migration_0011_update_LDAP_schema": "Actualizando el esquema de LDAP...",
"migration_0011_update_LDAP_database": "Actualizando la base de datos de LDAP...",
"migration_0011_rollback_success": "Revertido correctamente.",
"migration_0011_migration_failed_trying_to_rollback": "Migración fallida... intentando revertir el sistema.",
"migration_0011_migrate_permission": "Migrando permisos desde la configuración de las aplicaciones a LDAP...",
"migration_0011_LDAP_update_failed": "Actualización de LDAP fallida. Error: {error:s}",
"migration_0011_LDAP_config_dirty": "Parece que ha personalizado la configuración de LDAP. Para esta migración se necesita actualizar la configuración de LDAP.\nNecesita guardar su configuración actual, restaurar la configuración original con la orden «yunohost tools regen-conf -f» y reintentar después la migración",
"migration_0011_done": "Migración exitosa. Ahora puede gestionar los grupos de usuarios.",
"migration_0011_create_group": "Creando un grupo para cada usuario...",
"migration_0011_can_not_backup_before_migration": "Falló la copia de seguridad del sistema antes de la migración. Migración fallida. Error: {error:s}",
"migrations_list_conflict_pending_done": "No puede usar «--previous» y «--done» al mismo tiempo.",
"migrations_exclusive_options": "«--auto», «--skip», and «--force-rerun» son opciones mutuamente excluyentes.",
"migrations_failed_to_load_migration": "No se pudo cargar la migración {id}: {error}",
"migrations_dependencies_not_satisfied": "Ejecutar estas migraciones: «{dependencies_id}» antes de migrar {id}.",
"migrations_cant_reach_migration_file": "No se pudo acceder a los archivos de migración en la ruta «%s»",
"migrations_already_ran": "Esas migraciones ya se han realizado: {ids}",
"migration_0011_update_LDAP_schema": "Actualizando el esquema de LDAP",
"migration_0011_update_LDAP_database": "Actualizando la base de datos de LDAP",
"migration_0011_rollback_success": "Sistema revertido.",
"migration_0011_migration_failed_trying_to_rollback": "No se pudo migrar… intentando revertir el sistema.",
"migration_0011_migrate_permission": "Migrando permisos desde la configuración de las aplicaciones a LDAP",
"migration_0011_LDAP_update_failed": "No se pudo actualizar LDAP. Error: {error:s}",
"migration_0011_LDAP_config_dirty": "Parece que ha personalizado la configuración de LDAP. Para esta migración se necesita actualizar la configuración de LDAP.\nNecesita guardar su configuración actual, reiniciar la configuración original ejecutando «yunohost tools regen-conf -f» y reintentar la migración",
"migration_0011_done": "Migración finalizada. Ahora puede gestionar los grupos de usuarios.",
"migration_0011_create_group": "Creando un grupo para cada usuario",
"migration_0011_can_not_backup_before_migration": "El respaldo del sistema no se pudo completar antes de que la migración fallase. Error: {error:s}",
"migration_0011_backup_before_migration": "Creando un respaldo de la base de datos de LDAP y de la configuración de las aplicaciones antes de la migración real.",
"migration_0009_not_needed": "¿La migración ya ocurrió de algún modo? Omitiendo.",
"migration_0008_no_warning": "No se ha detectado ningún riesgo importante sobre la anulación de su configuración SSH ¡pero no existe una certeza absoluta ;)! Si permite a YunoHost anular su configuración actual, ejecute la migración. Por otra parte puede omitir la migración, aunque no se recomienda.",
"migration_0008_warning": "Si entiende esos avisos y permite a YunoHost anular su configuración actual, ejecute la migración. Por otra parte puede omitir la migración, aunque no se recomienda.",
"migration_0008_dsa": " - se desactivará la clave DSA. Así que podría tener que anular un aviso espeluznante de su cliente SSH y volver a comprobar la huella de su servidor;",
"migration_0008_root": " - no podrá conectarse como «root» a través de SSH. En su lugar debería usar el usuario de administración;",
"migration_0008_port": " - tendrá que conectarse usando el puerto 22 en vez de su actual puerto SSH personalizado. No dude en reconfigurarlo;",
"migration_0008_general_disclaimer": "Para mejorar la seguridad de su servidor, es recomendable permitir a YunoHost gestionar la configuración SSH. Su actual configuración SSH difiere de la configuración recomendada. Si permite a YunoHost reconfigurarla, la manera en la que conecta con su servidor a través de SSH cambiará en el siguiente modo:",
"migration_0009_not_needed": "La migración ya ocurrió de algún modo… (?) Omitiendo.",
"migration_0008_no_warning": "Ignorar su configuración SSH debería ser seguro ¡aunque esto no se puede prometer! Ejecute la migración para ignorarla. Por otra parte puede omitir la migración, aunque no se recomienda.",
"migration_0008_warning": "Si entiende esos avisos y quiere que YunoHost ignore su configuración actual, ejecute la migración. Por otra parte puede omitir la migración, aunque no se recomienda.",
"migration_0008_dsa": "• Se desactivará la clave DSA. Así que podría tener que anular un aviso espeluznante de su cliente SSH y volver a comprobar la huella de su servidor;",
"migration_0008_root": "• No podrá conectarse como «root» a través de SSH. En su lugar debe usar el usuario «admin»;",
"migration_0008_port": "• Tendrá que conectarse usando el puerto 22 en vez de su actual puerto SSH personalizado. No dude en reconfigurarlo;",
"migration_0008_general_disclaimer": "Para mejorar la seguridad de su servidor, es recomendable permitir a YunoHost gestionar la configuración de SSH. Su actual configuración de SSH difiere de la recomendación. Si permite a YunoHost reconfigurarla, la manera en la que conecta con su servidor a través de SSH cambiará así:",
"migration_0007_cannot_restart": "No se puede reiniciar SSH después de intentar cancelar la migración número 6.",
"migration_0007_cancelled": "YunoHost no ha podido mejorar el modo en el que se gestiona su configuración de SSH.",
"migration_0006_disclaimer": "YunoHost espera ahora que las contraseñas de «admin» y «root» estén sincronizadas. Al ejecutar esta migración, su contraseña de «root» será reemplazada por la contraseña de administración.",
"migration_0005_not_enough_space": "No hay suficiente espacio libre disponible en {path} para ejecutar la migración en este momento:(.",
"migration_0005_postgresql_96_not_installed": "¿¡Se encontró postgresql 9.4 para ser instalado pero no postgresql 9.6!? Algo raro podría haber ocurrido en su sistema:(…",
"migration_0005_postgresql_94_not_installed": "Postgresql no estaba instalado en su sistema. ¡Nada que hacer!",
"migration_0003_modified_files": "Tenga en cuenta que se encontró que los siguientes archivos fueron modificados manualmente y podrían ser sobrescritos al final de la actualización: {manually_modified_files}",
"migration_0007_cancelled": "No se pudo mejorar el modo en el que se gestiona su configuración de SSH.",
"migration_0006_disclaimer": "YunoHost espera ahora que las contraseñas de «admin» y «root» estén sincronizadas. Esta migración reemplaza su contraseña de «root» por la contraseña de «admin».",
"migration_0005_not_enough_space": "Tenga suficiente espacio libre disponible en {path} para ejecutar la migración.",
"migration_0005_postgresql_96_not_installed": "⸘PostgreSQL 9.4 está instalado pero no PostgreSQL 9.6‽ Algo raro podría haber ocurrido en su sistema:(…",
"migration_0005_postgresql_94_not_installed": "PostgreSQL no estaba instalado en su sistema. Nada que hacer.",
"migration_0003_modified_files": "Tenga en cuenta que se encontró que los siguientes archivos fueron modificados manualmente y podrían ser sobrescritos después de la actualización: {manually_modified_files}",
"migration_0003_problematic_apps_warning": "Tenga en cuenta que se detectaron las siguientes aplicaciones instaladas posiblemente problemáticas. Parece que no fueron instaladas desde una lista de aplicaciones o no estaban etiquetadas como «funciona». Así que no hay garantía de que aún funcionen después de la actualización: {problematic_apps}",
"migration_0003_general_warning": "Tenga en cuenta que esta migración es una operación delicada. Aunque el equipo de YunoHost hizo todo lo posible para revisarla y probarla, la migración aún podría romper parte del sistema o de las aplicaciones.\n\nPor lo tanto le recomendamos que:\n - Realice una copia de seguridad de cualquier dato crítico o aplicación. Más información en https://yunohost.org/backup;\n - Tenga paciencia tras iniciar la migración: dependiendo de su conexión a internet y de su hardware, podría tardar unas cuantas horas hasta que todo se actualice.\n\nAdemás, el puerto para SMTP usado por los clientes de correo externos (como Thunderbird o K9-Mail) cambió de 465 (SSL/TLS) a 587 (STARTTLS). El antiguo puerto 465 se cerrará automáticamente y el nuevo puerto 587 se abrirá en el cortafuegos. ¡Todos los usuarios *tendrán* que adaptar la configuración de sus clientes de correo por lo tanto!",
"migration_0003_still_on_jessie_after_main_upgrade": "Algo fue mal durante la actualización principal: ¿¡el sistema está aún en Jessie!? Para investigar el problema, vea {log}:s…",
"migration_0003_general_warning": "Tenga en cuenta que esta migración es una operación delicada. El equipo de YunoHost ha hecho todo lo posible para revisarla y probarla, pero la migración aún podría romper parte del sistema o de sus aplicaciones.\n\nPor lo tanto, se recomienda que:\n - Realice una copia de seguridad de cualquier dato crítico o aplicación. Más información en https://yunohost.org/backup;\n - Tenga paciencia tras iniciar la migración: dependiendo de su conexión a Internet y de su hardware, podría tardar unas cuantas horas hasta que todo se actualice.\n\nAdemás, el puerto para SMTP usado por los clientes de correo externos (como Thunderbird o K9-Mail) cambió de 465 (SSL/TLS) a 587 (STARTTLS). El antiguo puerto (465) se cerrará automáticamente y el nuevo puerto (587) se abrirá en el cortafuegos. Todos los usuarios *tendrán* que adaptar la configuración de sus clientes de correo por lo tanto.",
"migration_0003_still_on_jessie_after_main_upgrade": "Algo fue mal durante la actualización principal: ⸘el sistema está aún en Jessie‽ Para investigar el problema, vea {log}:s…",
"migration_0003_system_not_fully_up_to_date": "Su sistema no está totalmente actualizado. Realice una actualización normal antes de ejecutar la migración a Stretch.",
"migration_0003_not_jessie": "¡La distribución de Debian actual no es Jessie!",
"migration_0003_yunohost_upgrade": "Iniciando la actualización del paquete «yunohost»… La migración finalizará pero la actualización real ocurrirá justo después. Después de que la operación esté completada, podría tener que reiniciar sesión en la administración web.",
"migration_0003_yunohost_upgrade": "Iniciando la actualización del paquete YunoHost… La migración finalizará pero la actualización real ocurrirá inmediatamente después. Después de que la operación esté completada, podría tener que iniciar sesión en la página de administración de nuevo.",
"migration_0003_restoring_origin_nginx_conf": "Su archivo /etc/nginx/nginx.conf ha sido editado de algún modo. La migración lo devolverá a su estado original primero… El archivo anterior estará disponible como {backup_dest}.",
"migration_0003_fail2ban_upgrade": "Iniciando la actualización de «fail2ban»…",
"migration_0003_fail2ban_upgrade": "Iniciando la actualización de Fail2Ban…",
"migration_0003_main_upgrade": "Iniciando la actualización principal…",
"migration_0003_patching_sources_list": "Corrigiendo «sources.lists»…",
"migration_0003_start": "Iniciando migración a Stretch. El registro estará disponible en {logfile}.",
"migration_description_0012_postgresql_password_to_md5_authentication": "Forzar a la autentificación de postgresql a usar md5 para las conexiones locales",
"migration_description_0012_postgresql_password_to_md5_authentication": "Forzar a la autentificación de PostgreSQL a usar MD5 para las conexiones locales",
"migration_description_0011_setup_group_permission": "Configurar grupo de usuario y configurar permisos para aplicaciones y servicios",
"migration_description_0010_migrate_to_apps_json": "Eliminar la obsoleta «appslists» y usar la nueva lista unificada «apps.json»",
"migration_description_0010_migrate_to_apps_json": "Eliminar las listas de aplicaciones («appslists») obsoletas y usar en su lugar la nueva lista unificada «apps.json»",
"migration_description_0009_decouple_regenconf_from_services": "Separar el mecanismo «regen-conf» de los servicios",
"migration_description_0008_ssh_conf_managed_by_yunohost_step2": "Permitir que la configuración de SSH la gestione YunoHost (paso 2, manual)",
"migration_description_0007_ssh_conf_managed_by_yunohost_step1": "Permitir que la configuración de SSH la gestione YunoHost (paso 1, automático)",
"migration_description_0006_sync_admin_and_root_passwords": "Sincronizar las contraseñas de «admin» y «root»",
"migration_description_0005_postgresql_9p4_to_9p6": "Migrar las bases de datos de postgresql 9.4 a 9.6",
"migration_description_0005_postgresql_9p4_to_9p6": "Migrar las bases de datos de PostgreSQL 9.4 a 9.6",
"migration_description_0004_php5_to_php7_pools": "Reconfigurar los «pools» de PHP para usar PHP 7 en vez de 5",
"migration_description_0003_migrate_to_stretch": "Actualizar el sistema a Debian Stretch y YunoHost 3.0",
"migration_description_0002_migrate_to_tsig_sha256": "Mejorar la seguridad de la TSIG de dyndns usando SHA512 en vez de MD5",
"migration_description_0002_migrate_to_tsig_sha256": "Mejore la seguridad de las actualizaciones de TSIG de DynDNS usando SHA-512 en vez de MD5",
"migration_description_0001_change_cert_group_to_sslcert": "Cambiar los permisos de grupo de certificados de «metronome» a «ssl-cert»",
"migrate_tsig_not_needed": "Parece que no usa un dominio dyndns ¡así que no es necesario migrar!",
"migrate_tsig_not_needed": "Parece que no usa un dominio de DynDNS, así que no es necesario migrar.",
"migrate_tsig_wait_4": "30 segundos…",
"migrate_tsig_wait_3": "1 min. …",
"migrate_tsig_wait_2": "2 min. …",
"migrate_tsig_wait": "Esperar 3 min. para que el servidor dyndns tenga en cuenta la nueva clave…",
"migrate_tsig_start": "Detectado algoritmo de clave insuficientemente seguro para la firma TSIG del dominio «{domain}», iniciando migración al más seguro hmac-sha512",
"migrate_tsig_failed": "Error al migrar el dominio de dyndns {domain} a hmac-sha512, revertiendo. Error: {error_code} - {error}",
"migrate_tsig_end": "Terminada la migración a hmac-sha512",
"migrate_tsig_wait": "Esperando tres minutos para que el servidor de DynDNS tenga en cuenta la nueva clave…",
"migrate_tsig_start": "Detectado algoritmo de clave insuficientemente seguro para la firma TSIG del dominio «{domain}», iniciando migración al más seguro HMAC-SHA-512",
"migrate_tsig_failed": "No se pudo migrar el dominio de DynDNS «{domain}» a HMAC-SHA-512, revertiendo. Error: {error_code}, {error}",
"migrate_tsig_end": "Terminada la migración a HMAC-SHA-512",
"mail_unavailable": "Esta dirección de correo está reservada y será asignada automáticamente al primer usuario",
"mailbox_disabled": "Mailbox desactivado para usuario {user:s}",
"mailbox_disabled": "Correo desactivado para usuario {user:s}",
"log_tools_reboot": "Reiniciar el servidor",
"log_tools_shutdown": "Apagar el servidor",
"log_tools_upgrade": "Actualizar paquetes del sistema",
"log_tools_postinstall": "Posinstalación del servidor YunoHost",
"log_tools_migrations_migrate_forward": "Migrar hacia adelante",
"log_tools_maindomain": "Convertir «{}» en dominio principal",
"log_tools_maindomain": "Convertir «{}» en el dominio principal",
"log_user_permission_remove": "Actualizar permiso «{}»",
"log_user_permission_add": "Actualizar permiso «{}»",
"log_user_update": "Actualizar información del usuario «{}»",
"log_user_update": "Actualizar la información de usuario de «{}»",
"log_user_group_update": "Actualizar grupo «{}»",
"log_user_group_delete": "Eliminar grupo «{}»",
"log_user_group_add": "Añadir grupo «{}»",
"log_user_delete": "Eliminar usuario «{}»",
"log_user_create": "Añadir usuario «{}»",
"log_regen_conf": "Regenerar la configuración del sistema «{}»",
"log_letsencrypt_cert_renew": "Renovar el certificado «{}» de Let's encrypt",
"log_letsencrypt_cert_renew": "Renovar el certificado «{}» de Let's Encrypt",
"log_selfsigned_cert_install": "Instalar certificado autofirmado en el dominio «{}»",
"log_permission_update": "Actualizar permiso «{}» para la aplicación «{}»",
"log_permission_remove": "Eliminar permiso «{}»",
"log_permission_add": "Añadir permiso «{}» para la aplicación «{}»",
"log_letsencrypt_cert_install": "Instalar certificado de Let's encrypt en el dominio «{}»",
"log_permission_add": "Añadir el permiso «{}» para la aplicación «{}»",
"log_letsencrypt_cert_install": "Instalar un certificado de Let's Encrypt en el dominio «{}»",
"log_dyndns_update": "Actualizar la IP asociada con su subdominio de YunoHost «{}»",
"log_dyndns_subscribe": "Subscribirse a un subdomino de YunoHost «{}»",
"log_domain_remove": "Eliminar el dominio «{}» de la configuración del sistema",
@ -521,7 +521,7 @@
"log_app_upgrade": "Actualizar la aplicación «{}»",
"log_app_remove": "Eliminar la aplicación «{}»",
"log_app_install": "Instalar la aplicación «{}»",
"log_app_change_url": "Cambiar la url de la aplicación «{}»",
"log_app_change_url": "Cambiar el URL de la aplicación «{}»",
"log_app_removelist": "Eliminar una lista de aplicaciones",
"log_app_fetchlist": "Añadir una lista de aplicaciones",
"log_app_clearaccess": "Eliminar todos los accesos a «{}»",
@ -529,26 +529,26 @@
"log_app_addaccess": "Añadir acceso a «{}»",
"log_operation_unit_unclosed_properly": "La unidad de operación no se ha cerrado correctamente",
"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": "¡La operación «{desc}» ha fallado! Para obtener ayuda, comparta el registro completo de esta operación ejecutando la orden «yunohost log display {name} --share»",
"log_link_to_failed_log": "¡La operación «{desc}» ha fallado! Para obtener ayuda, <a href=\"#/tools/logs/{name}\">proporcione el registro completo de esta operación pulsando aquí</a>",
"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 display {name} --share»",
"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 display {name}»",
"log_link_to_log": "Registro completo de esta operación: «<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>»",
"log_category_404": "La categoría de registro «{category}» no existe",
"log_corrupted_md_file": "El archivo de metadatos yaml asociado con el registro está dañado: «{md_file}\nError: {error}»",
"hook_json_return_error": "Error al leer la respuesta del gancho {path:s}. Error: {msg:s}. Contenido sin procesar: {raw_content}",
"group_update_failed": "Error en la actualización del grupo «{group}»",
"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:s}. Error: {msg:s}. Contenido sin procesar: {raw_content}",
"group_update_failed": "No se pudo actualizar el grupo «{group}»: {error}",
"group_updated": "Grupo «{group}» actualizado",
"group_unknown": "Grupo {group:s} desconocido",
"group_info_failed": "Error en la información del grupo",
"group_unknown": "El grupo «{group:s}» es desconocido",
"group_info_failed": "No se pudo mostrar la información del grupo",
"group_deletion_not_allowed": "No se puede eliminar el grupo {group:s} manualmente.",
"group_deletion_failed": "Error al eliminar el grupo «{group}»",
"group_deletion_failed": "No se pudo eliminar el grupo «{group}»: {error}",
"group_deleted": "Eliminado el grupo «{group}»",
"group_creation_failed": "Error al crear el grupo «{group}»",
"group_created": "Grupo «{group}» creado correctamente",
"group_creation_failed": "No se pudo crear el grupo «{group}»: {error}",
"group_created": "Creado el grupo «{group}»",
"group_name_already_exist": "El grupo {name:s} ya existe",
"group_already_disallowed": "El grupo '{group:s}' ya tiene desactivado el permiso «{permission:s}» para la aplicación «{app:s}»",
"group_already_allowed": "El grupo '{group:s}' ya tiene activado el permiso «{permission:s}» para la aplicación «{app:s}»",
"good_practices_about_admin_password": "Va a determinar una nueva contraseña de administración. La contraseña debería tener al menos 8 caracteres, aunque es una buena práctica usar contraseñas más extensas (esto es, una frase) y/o usar caracteres de varias clases (mayúsculas, minúsculas, números y caracteres especiales).",
"group_already_disallowed": "El grupo «{group:s}» ya tiene desactivado el permiso «{permission:s}» para la aplicación «{app:s}»",
"group_already_allowed": "El grupo «{group:s}» ya tiene activado el permiso «{permission:s}» para la aplicación «{app:s}»",
"good_practices_about_admin_password": "Va a establecer una nueva contraseña de administración. La contraseña debería tener al menos 8 caracteres, aunque es una buena práctica usar una contraseña más extensa (básicamente una frase) y/o usar caracteres de varias clases (mayúsculas, minúsculas, números y caracteres especiales).",
"global_settings_unknown_type": "Situación imprevista, la configuración {setting:s} parece tener el tipo {unknown_type:s} pero no es un tipo compatible con el sistema.",
"global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Permitir el uso de la llave (obsoleta) DSA para la configuración del demonio SSH",
"global_settings_unknown_setting_from_settings_file": "Clave desconocida en la configuración: «{setting_key:s}», desechada y guardada en /etc/yunohost/settings-unknown.json",
@ -556,53 +556,86 @@
"global_settings_setting_security_ssh_compatibility": "Compromiso entre compatibilidad y seguridad para el servidor SSH. Afecta al cifrado (y otros aspectos relacionados con la seguridad)",
"global_settings_setting_security_password_user_strength": "Seguridad de la contraseña de usuario",
"global_settings_setting_security_password_admin_strength": "Seguridad de la contraseña del administrador",
"global_settings_setting_security_nginx_compatibility": "Compromiso entre compatibilidad y seguridad para el servidor web nginx. Afecta al cifrado (y otros aspectos relacionados con la seguridad)",
"global_settings_setting_security_nginx_compatibility": "Compromiso entre compatibilidad y seguridad para el servidor web NGINX. Afecta al cifrado (y otros aspectos relacionados con la seguridad)",
"global_settings_setting_example_string": "Ejemplo de opción de cadena",
"global_settings_setting_example_int": "Ejemplo de opción «int»",
"global_settings_setting_example_enum": "Ejemplo de opción «enum»",
"global_settings_setting_example_bool": "Ejemplo de opción booleana",
"global_settings_reset_success": "Éxito. Se ha respaldado su configuración previa en {path:s}",
"global_settings_reset_success": "Respaldada la configuración previa en {path:s}",
"global_settings_key_doesnt_exists": "La clave «{settings_key:s}» no existe en la configuración global, puede ver todas las claves disponibles ejecutando «yunohost settings list»",
"global_settings_cant_write_settings": "Error al escribir el archivo de configuración, motivo: {reason:s}",
"global_settings_cant_serialize_settings": "Error al seriar los datos de configuración, motivo: {reason:s}",
"global_settings_cant_open_settings": "Error al abrir el archivo de configuración, motivo: {reason:s}",
"global_settings_bad_type_for_setting": "Tipo erróneo para la configuración {setting:s}, obtuvo {received_type:s}, excepto {expected_type:s}",
"global_settings_bad_choice_for_enum": "Mala elección para la configuración {setting:s}, obtuvo «{choice:s}» pero las opciones disponibles son: {available_choices:s}",
"global_settings_cant_write_settings": "No se pudo guardar el archivo de configuración, motivo: {reason:s}",
"global_settings_cant_serialize_settings": "No se pudo seriar los datos de configuración, motivo: {reason:s}",
"global_settings_cant_open_settings": "No se pudo abrir el archivo de configuración, motivo: {reason:s}",
"global_settings_bad_type_for_setting": "Tipo erróneo para la configuración {setting:s}, obtuvo {received_type:s}, esperado {expected_type:s}",
"global_settings_bad_choice_for_enum": "Opción errónea para la configuración {setting:s}, obtuvo «{choice:s}» pero las opciones disponibles son: {available_choices:s}",
"file_does_not_exist": "El archivo {path:s} no existe.",
"error_when_removing_sftpuser_group": "Error al probar «remove sftpusers group»",
"error_when_removing_sftpuser_group": "No se pudo eliminar el grupo sftpusers",
"edit_permission_with_group_all_users_not_allowed": "No puede editar el permiso para el grupo «all_users», utilice «yunohost user permission clear APLICACIÓN» o «yunohost user permission add APLICACIÓN -u USUARIO».",
"edit_group_not_allowed": "No tiene permiso para editar el grupo {group:s}",
"dyndns_could_not_check_available": "No se pudo comprobar si {domain:s} está disponible en {provider:s}.",
"domain_dyndns_dynette_is_unreachable": "No se pudo conectar al dynette de YunoHost, o su YunoHost no está correctamente conectado a internet o el servidor dynette está caído. Error: {error}",
"domain_dns_conf_is_just_a_recommendation": "Esta orden muestra cuál es la configuración *recomendada*. No configura el DNS. Es su responsabilidad configurar la zona de DNS en su registrador según esta recomendación.",
"domain_dyndns_dynette_is_unreachable": "No se pudo conectar a dynette de YunoHost. O su YunoHost no está correctamente conectado a Internet o el servidor dynette está caído. Error: {error}",
"domain_dns_conf_is_just_a_recommendation": "Esta orden muestra la configuración *recomendada*. No configura el DNS en realidad. Es su responsabilidad configurar la zona de DNS en su registrador según esta recomendación.",
"dpkg_lock_not_available": "Esta orden no se puede ejecutar en este momento porque otro programa parece que está usando el bloqueo de dpkg (el gestor de paquetes del sistema)",
"dpkg_is_broken": "No puede hacer esto en este momento porque dpkg/apt (los gestores de paquetes del sistema) parecen estar en un estado roto... Puede tratar de solucionar este problema conectando a través de SSH y ejecutando `sudo dpkg --configure -a`.",
"confirm_app_install_thirdparty": AVISO! Instalar aplicaciones de terceros podría comprometer la integridad y seguridad de su sistema. Probablemente NO debería instalarlas salvo que sepa lo que está haciendo. ¿Está dispuesto a correr ese riesgo? [{answers:s}] ",
"confirm_app_install_danger": AVISO! Esta aplicación es aún experimental (si no está funcionando expresamente) y ¡es probable que rompa su sistema! Probablemente NO debería instalarla salvo que sepa lo que está haciendo. ¿Está dispuesto a correr ese riesgo? [{answers:s}] ",
"confirm_app_install_thirdparty": PELIGRO! Esta aplicación no forma parte del catálogo de aplicaciones de YunoHost. Instalar aplicaciones de terceros podría comprometer la integridad y seguridad de su sistema. Probablemente NO debería instalarla salvo que sepa lo que está haciendo. No tendrá NINGUNA AYUDA si esta aplicación no funciona o rompe su sistema… Si está dispuesto a aceptar ese riesgo de todas formas, escriba «{answers:s}»",
"confirm_app_install_danger": PELIGRO! ¡Esta aplicación es conocida por ser aún experimental (o no funciona explícitamente)! Probablemente NO debería instalarla salvo que sepa lo que está haciendo. No tendrá NINGUNA AYUDA si esta aplicación no funciona o rompe su sistema… Si está dispuesto a aceptar ese riesgo de todas formas, escriba «{answers:s}»",
"confirm_app_install_warning": "Aviso: esta aplicación puede funcionar pero no está bien integrada en YunoHost. Algunas herramientas como la autentificación única y respaldo/restauración podrían no estar disponibles. ¿Instalar de todos modos? [{answers:s}] ",
"backup_unable_to_organize_files": "No se pueden organizar los archivos en el archivo con el método rápido",
"backup_unable_to_organize_files": "No se pudo usar el método rápido de organización de los archivos en el archivo",
"backup_permission": "Permiso de respaldo para la aplicación {app:s}",
"backup_output_symlink_dir_broken": "Tiene un enlace simbólico roto en vez del directorio «{path:s}» de sus archivos. Puede que tenga una configuración específica para respaldar sus datos en otro sistema de archivos, en este caso probablemente olvidó remontar o conectar su disco duro o clave usb.",
"backup_output_symlink_dir_broken": "El directorio de su archivo «{path:s}» es un enlace simbólico roto. Tal vez olvidó (re)montarlo o conectarlo al medio de almacenamiento al que apunta.",
"backup_mount_archive_for_restore": "Preparando el archivo para la restauración…",
"backup_method_tar_finished": "Creado el archivo de respaldo tar",
"backup_method_tar_finished": "Creado el archivo TAR de respaldo",
"backup_method_custom_finished": "Terminado el método «{method:s}» de respaldo personalizado",
"backup_method_copy_finished": "Terminada la copia de seguridad",
"backup_method_borg_finished": "Terminado el respaldo en borg",
"backup_custom_backup_error": "Fallo del método de respaldo personalizado en el paso «copia de seguridad»",
"backup_method_borg_finished": "Terminado el respaldo en Borg",
"backup_custom_backup_error": "El método de respaldo personalizado no pudo superar el paso de «copia de seguridad»",
"backup_actually_backuping": "Creando un archivo de respaldo de los archivos obtenidos…",
"ask_new_path": "Nueva ruta",
"ask_new_domain": "Nuevo dominio",
"apps_permission_restoration_failed": "El permiso «{permission:s}» para la restauración de la aplicación {app:s} ha fallado",
"apps_permission_restoration_failed": "Otorgar el permiso «{permission:s}» para restaurar {app:s}",
"apps_permission_not_found": "No se han encontrado permisos para las aplicaciones instaladas",
"app_upgrade_several_apps": "Las siguientes aplicaciones se actualizarán: {apps}",
"app_start_restore": "Restaurando aplicación {app}…",
"app_start_backup": "Obteniendo archivos de respaldo para {app}…",
"app_start_remove": "Eliminando aplicación {app}…",
"app_start_install": "Instalando aplicación {app}…",
"app_start_restore": "Restaurando aplicación «{app}»…",
"app_start_backup": "Obteniendo archivos para el respaldo de «{app}»…",
"app_start_remove": "Eliminando aplicación «{app}»…",
"app_start_install": "Instalando aplicación «{app}»…",
"app_not_upgraded": "Error al actualizar la aplicación «{failed_app}» y como consecuencia se han cancelado las actualizaciones de las siguientes aplicaciones: {apps}",
"app_action_cannot_be_ran_because_required_services_down": "Esta aplicación necesita algunos servicios que no están funcionando ahora. Antes de continuar, debería intentar reiniciar los siguientes servicios (y posiblemente investigar por qué no funcionan): {services}",
"already_up_to_date": "¡Nada que hacer! ¡Todo está actualizado!",
"app_action_cannot_be_ran_because_required_services_down": "Estos servicios necesarios deberían estar funcionando para ejecutar esta acción: {services}. Pruebe a reiniciarlos para continuar (y posiblemente investigar por qué están caídos).",
"already_up_to_date": "Nada que hacer. Todo está actualizado.",
"admin_password_too_long": "Elija una contraseña de menos de 127 caracteres",
"aborting": "Cancelando.",
"app_upgrade_stopped": "Se ha detenido la actualización de todas las aplicaciones para prevenir un posible daño porque la aplicación anterior no se pudo actualizar"
"app_upgrade_stopped": "Se ha detenido la actualización de todas las aplicaciones para prevenir un posible daño porque una aplicación no se pudo actualizar",
"app_action_broke_system": "Esta acción parece que ha roto estos importantes servicios: {services}",
"operation_interrupted": "¿Ha sido interrumpida la operación manualmente?",
"apps_already_up_to_date": "Todas las aplicaciones están ya actualizadas",
"dyndns_provider_unreachable": "No se puede conectar con el proveedor de Dyndns {provider}: o su YunoHost no está correctamente conectado a Internet o el servidor de dynette está caído.",
"group_already_exist": "El grupo {group} ya existe",
"group_already_exist_on_system": "El grupo {group} ya existe en los grupos del sistema",
"group_cannot_be_edited": "El grupo {group} no se puede editar manualmente.",
"group_cannot_be_deleted": "El grupo {group} no se puede eliminar manualmente.",
"group_user_already_in_group": "El usuario {user} ya está en el grupo {group}",
"group_user_not_in_group": "El usuario {user} no está en el grupo {group}",
"log_permission_create": "Crear permiso «{}»",
"log_permission_delete": "Eliminar permiso «{}»",
"log_permission_urls": "Actualizar URLs relacionadas con el permiso «{}»",
"log_user_group_create": "Crear grupo «{}»",
"log_user_permission_update": "Actualizar los accesos para el permiso «{}»",
"log_user_permission_reset": "Restablecer permiso «{}»",
"migration_0011_failed_to_remove_stale_object": "No se pudo eliminar el objeto obsoleto {dn}: {error}",
"permission_already_allowed": "El grupo «{group}» ya tiene el permiso «{permission}» activado",
"permission_already_disallowed": "El grupo «{group}» ya tiene el permiso «{permission}» desactivado",
"permission_cannot_remove_main": "No está permitido eliminar un permiso principal",
"user_already_exists": "El usuario «{user}» ya existe",
"app_full_domain_unavailable": "Lamentablemente esta aplicación tiene que instalarse en un dominio propio pero ya hay otras aplicaciones instaladas en el dominio «{domain}». Podría usar un subdomino dedicado a esta aplicación en su lugar.",
"app_install_failed": "No se pudo instalar {app}: {error}",
"app_install_script_failed": "Ha ocurrido un error en el guión de instalación de la aplicación",
"group_cannot_edit_all_users": "El grupo «all_users» no se puede editar manualmente. Es un grupo especial destinado a contener todos los usuarios registrados en YunoHost",
"group_cannot_edit_visitors": "El grupo «visitors» no se puede editar manualmente. Es un grupo especial que representa a los visitantes anónimos",
"group_cannot_edit_primary_group": "El grupo «{group}» no se puede editar manualmente. Es el grupo primario destinado a contener solo un usuario específico.",
"log_permission_url": "Actualizar la URL relacionada con el permiso «{}»",
"migration_0011_slapd_config_will_be_overwritten": "Parece que ha editado manualmente la configuración de slapd. Para esta migración crítica, YunoHost necesita forzar la actualización de la configuración de slapd. Los archivos originales se respaldarán en {conf_backup_folder}.",
"permission_already_up_to_date": "El permiso no se ha actualizado porque las peticiones de incorporación o eliminación ya coinciden con el estado actual.",
"permission_currently_allowed_for_visitors": "Este permiso se concede actualmente a los visitantes además de otros grupos. Probablemente quiere o eliminar el permiso de «visitors» o eliminar los otros grupos a los que está otorgado actualmente.",
"permission_currently_allowed_for_all_users": "Este permiso se concede actualmente a todos los usuarios además de los otros grupos. Probablemente quiere o eliminar el permiso de «all_users» o eliminar los otros grupos a los que está otorgado actualmente.",
"permission_require_account": "El permiso {permission} solo tiene sentido para usuarios con una cuenta y, por lo tanto, no se puede activar para visitantes."
}

View file

@ -17,11 +17,11 @@
"app_manifest_invalid": "Manifeste dapplication incorrect : {error}",
"app_no_upgrade": "Aucune application à mettre à jour",
"app_not_correctly_installed": "{app:s} semble être mal installé",
"app_not_installed": "L'application « {app:s} » nest pas installée. Voici la liste des applications installées: {all_apps}",
"app_not_installed": "Nous navons pas trouvé lapplication « {app:s} » dans la liste des applications installées: {all_apps}",
"app_not_properly_removed": "{app:s} na pas été supprimé correctement",
"app_package_need_update": "Le paquet de lapplication {app} doit être mis à jour pour être en adéquation avec les changements de YunoHost",
"app_recent_version_required": "{app:s} nécessite une version plus récente de YunoHost",
"app_removed": "{app:s} a été supprimé",
"app_removed": "{app:s} supprimé",
"app_requirements_checking": "Vérification des paquets requis pour {app} …",
"app_requirements_failed": "Impossible de satisfaire les pré-requis pour {app} : {error}",
"app_requirements_unmeet": "Les pré-requis de {app} ne sont pas satisfaits, le paquet {pkgname} ({version}) doit être {spec}",
@ -29,11 +29,11 @@
"app_unknown": "Application inconnue",
"app_unsupported_remote_type": "Ce type de commande à distance utilisé pour cette application n'est pas supporté",
"app_upgrade_failed": "Impossible de mettre à jour {app:s}",
"app_upgraded": "{app:s} a été mis à jour",
"appslist_fetched": "La liste dapplications {appslist:s} a été récupérée",
"appslist_removed": "La liste dapplications {appslist:s} a été supprimée",
"appslist_retrieve_error": "Impossible de récupérer la liste dapplications distante {appslist:s} : {error:s}",
"appslist_unknown": "La liste dapplications {appslist:s} est inconnue.",
"app_upgraded": "{app:s} mis à jour",
"appslist_fetched": "La liste dapplications mise à jour '{appslist:s}'",
"appslist_removed": "La liste d'applications '{appslist:s}' a été supprimée",
"appslist_retrieve_error": "Impossible de récupérer la liste dapplications distante '{appslist:s}' : {error:s}",
"appslist_unknown": "La liste dapplications '{appslist:s}' est inconnue.",
"ask_current_admin_password": "Mot de passe dadministration actuel",
"ask_email": "Adresse de courriel",
"ask_firstname": "Prénom",
@ -46,13 +46,13 @@
"backup_app_failed": "Impossible de sauvegarder lapplication '{app:s}'",
"backup_archive_app_not_found": "Lapplication '{app:s}' na pas été trouvée dans larchive de la sauvegarde",
"backup_archive_hook_not_exec": "Le script « {hook:s} » n'a pas été exécuté dans cette sauvegarde",
"backup_archive_name_exists": "Une archive de sauvegarde avec ce nom existe déjà",
"backup_archive_name_exists": "Une archive de sauvegarde avec ce nom existe déjà.",
"backup_archive_name_unknown": "Larchive locale de sauvegarde nommée '{name:s}' est inconnue",
"backup_archive_open_failed": "Impossible douvrir larchive de sauvegarde",
"backup_archive_open_failed": "Impossible douvrir larchive de la sauvegarde",
"backup_cleaning_failed": "Impossible de nettoyer le dossier temporaire de sauvegarde",
"backup_created": "Sauvegarde terminée",
"backup_creating_archive": "Création de larchive de sauvegarde …",
"backup_creation_failed": "Impossible de créer la sauvegarde",
"backup_creation_failed": "Impossible de créer l'archive de la sauvegarde",
"backup_delete_error": "Impossible de supprimer '{path:s}'",
"backup_deleted": "La sauvegarde a été supprimée",
"backup_extracting_archive": "Extraction de larchive de sauvegarde …",
@ -75,9 +75,9 @@
"dnsmasq_isnt_installed": "dnsmasq ne semble pas être installé, veuillez lancer 'apt-get remove bind9 && apt-get install dnsmasq'",
"domain_cert_gen_failed": "Impossible de générer le certificat",
"domain_created": "Le domaine a été créé",
"domain_creation_failed": "Impossible de créer le domaine",
"domain_creation_failed": "Impossible de créer le domaine {domain}: {error}",
"domain_deleted": "Le domaine a été supprimé",
"domain_deletion_failed": "Impossible de supprimer le domaine",
"domain_deletion_failed": "Impossible de supprimer le domaine {domain}: {error}",
"domain_dyndns_already_subscribed": "Vous avez déjà souscris à un domaine DynDNS",
"domain_dyndns_invalid": "Domaine incorrect pour un usage avec DynDNS",
"domain_dyndns_root_unknown": "Domaine DynDNS principal inconnu",
@ -88,15 +88,15 @@
"domain_zone_not_found": "Fichier de zone DNS introuvable pour le domaine {:s}",
"done": "Terminé",
"downloading": "Téléchargement en cours …",
"dyndns_cron_installed": "La tâche cron pour le domaine DynDNS a été installée",
"dyndns_cron_installed": "La tâche cron pour le domaine DynDNS a été créée",
"dyndns_cron_remove_failed": "Impossible de supprimer la tâche cron DynDNS parce que: {error}",
"dyndns_cron_removed": "La tâche cron pour le domaine DynDNS a été enlevée",
"dyndns_cron_removed": "La tâche cron pour le domaine DynDNS enlevée",
"dyndns_ip_update_failed": "Impossible de mettre à jour ladresse IP sur le domaine DynDNS",
"dyndns_ip_updated": "Votre adresse IP a été mise à jour pour le domaine DynDNS",
"dyndns_key_generating": "La clé DNS est en cours de génération, cela peut prendre un certain temps …",
"dyndns_ip_updated": "Mise à jour de votre IP pour le domaine DynDNS",
"dyndns_key_generating": "Génération de la clé DNS ... , cela peut prendre un certain temps.",
"dyndns_key_not_found": "Clé DNS introuvable pour le domaine",
"dyndns_no_domain_registered": "Aucun domaine na été enregistré avec DynDNS",
"dyndns_registered": "Le domaine DynDNS a été enregistré",
"dyndns_no_domain_registered": "Aucun domaine enregistré avec DynDNS",
"dyndns_registered": "Domaine DynDNS enregistré",
"dyndns_registration_failed": "Impossible denregistrer le domaine DynDNS : {error:s}",
"dyndns_unavailable": "Le domaine {domain:s} est indisponible.",
"executing_command": "Exécution de la commande '{command:s}' …",
@ -104,8 +104,8 @@
"extracting": "Extraction en cours …",
"field_invalid": "Champ incorrect : '{:s}'",
"firewall_reload_failed": "Impossible de recharger le pare-feu",
"firewall_reloaded": "Le pare-feu a été rechargé",
"firewall_rules_cmd_failed": "Certaines règles du pare-feu nont pas pu être appliquées. Pour plus dinformations, consultez le journal.",
"firewall_reloaded": "Pare-feu rechargé",
"firewall_rules_cmd_failed": "Certaines règles du pare-feu nont pas pu être appliquées. Plus d'info dans le journal de log.",
"format_datetime_short": "%d/%m/%Y %H:%M",
"hook_argument_missing": "Argument manquant : '{:s}'",
"hook_choice_invalid": "Choix incorrect : '{:s}'",
@ -114,28 +114,28 @@
"hook_list_by_invalid": "Propriété invalide pour lister les actions par celle-ci",
"hook_name_unknown": "Nom de l'action '{name:s}' inconnu",
"installation_complete": "Installation terminée",
"installation_failed": "Échec de linstallation",
"installation_failed": "Quelque chose s'est mal passé lors de l'installation",
"ip6tables_unavailable": "Vous ne pouvez pas jouer avec ip6tables ici. Vous êtes soit dans un conteneur, soit votre noyau ne le prend pas en charge",
"iptables_unavailable": "Vous ne pouvez pas jouer avec iptables ici. Vous êtes soit dans un conteneur, soit votre noyau ne le prend pas en charge",
"ldap_initialized": "Lannuaire LDAP a été initialisé",
"ldap_initialized": "Lannuaire LDAP initialisé",
"license_undefined": "indéfinie",
"mail_alias_remove_failed": "Impossible de supprimer lalias de courriel '{mail:s}'",
"mail_domain_unknown": "Le domaine '{domain:s}' pour l'adresse de courriel est inconnu",
"mail_domain_unknown": "Le domaine '{domain:s}' de cette adress de courriel n'est pas valide. Merci d'utiliser un domain administré par ce serveur.",
"mail_forward_remove_failed": "Impossible de supprimer le courriel de transfert '{mail:s}'",
"maindomain_change_failed": "Impossible de modifier le domaine principal",
"maindomain_changed": "Le domaine principal a été modifié",
"monitor_disabled": "La supervision du serveur a été désactivé",
"monitor_enabled": "La supervision du serveur a été activé",
"maindomain_changed": "Le domaine principal modifié",
"monitor_disabled": "Surveillance du serveur est maintenant arrêté",
"monitor_enabled": "La supervision du serveur est maintenant allumée",
"monitor_glances_con_failed": "Impossible de se connecter au serveur Glances",
"monitor_not_enabled": "Le suivi de létat du serveur nest pas activé",
"monitor_period_invalid": "Période de temps incorrecte",
"monitor_stats_file_not_found": "Le fichier de statistiques est introuvable",
"monitor_stats_file_not_found": "Impossible de trouver le fichier de statistiques",
"monitor_stats_no_update": "Aucune donnée de létat du serveur à mettre à jour",
"monitor_stats_period_unavailable": "Aucune statistique nest disponible pour la période",
"mountpoint_unknown": "Point de montage inconnu",
"mysql_db_creation_failed": "Impossible de créer la base de données MySQL",
"mysql_db_init_failed": "Impossible dinitialiser la base de données MySQL",
"mysql_db_initialized": "La base de données MySQL a été initialisée",
"mysql_db_init_failed": "Impossible d'initialiser la base de données MySQL",
"mysql_db_initialized": "La base de données MySQL est maintenant initialisée",
"network_check_mx_ko": "Lenregistrement DNS MX nest pas défini",
"network_check_smtp_ko": "Le trafic courriel sortant (port 25 SMTP) semble bloqué par votre réseau",
"network_check_smtp_ok": "Le trafic courriel sortant (port 25 SMTP) nest pas bloqué",
@ -155,7 +155,7 @@
"path_removal_failed": "Impossible de supprimer le chemin {:s}",
"pattern_backup_archive_name": "Doit être un nom de fichier valide avec un maximum de 30 caractères, et composé de caractères alphanumériques et -_. uniquement",
"pattern_domain": "Doit être un nom de domaine valide (ex : mon-domaine.fr)",
"pattern_email": "Doit être une adresse de courriel valide (ex. : pseudo@domaine.fr)",
"pattern_email": "Doit être une adresse de courriel valide (ex. : pseudo@example.com)",
"pattern_firstname": "Doit être un prénom valide",
"pattern_lastname": "Doit être un nom valide",
"pattern_listname": "Doit être composé uniquement de caractères alphanumériques et de tirets bas (aussi appelé tiret du 8 ou underscore)",
@ -173,7 +173,7 @@
"restore_already_installed_app": "Une application est déjà installée avec lidentifiant '{app:s}'",
"restore_app_failed": "Impossible de restaurer lapplication '{app:s}'",
"restore_cleaning_failed": "Impossible de nettoyer le dossier temporaire de restauration",
"restore_complete": "Restauration terminée",
"restore_complete": "Restauré",
"restore_confirm_yunohost_installed": "Voulez-vous vraiment restaurer un système déjà installé ? [{answers:s}]",
"restore_failed": "Impossible de restaurer le système",
"restore_hook_unavailable": "Le script de restauration '{part:s}' nest pas disponible sur votre système, et ne l'est pas non plus dans larchive",
@ -182,8 +182,8 @@
"restore_running_hooks": "Exécution des scripts de restauration …",
"service_add_configuration": "Ajout du fichier de configuration {file:s}",
"service_add_failed": "Impossible dajouter le service '{service:s}'",
"service_added": "Le service '{service:s}' a été ajouté",
"service_already_started": "Le service '{service:s}' est déjà démarré",
"service_added": "Le service '{service:s}' ajouté",
"service_already_started": "Le service '{service:s}' est déjà en cours d'exécution",
"service_already_stopped": "Le service '{service:s}' est déjà arrêté",
"service_cmd_exec_failed": "Impossible dexécuter la commande '{command:s}'",
"service_conf_file_backed_up": "Le fichier de configuration '{conf}' a été sauvegardé dans '{backup}'",
@ -204,7 +204,7 @@
"service_disabled": "Le service '{service:s}' a été désactivé",
"service_enable_failed": "Impossible dactiver le service '{service:s}'\n\nJournaux historisés récents : {logs:s}",
"service_enabled": "Le service '{service:s}' a été activé",
"service_no_log": "Aucun journal historisé à afficher pour le service '{service:s}'",
"service_no_log": "Aucun journal à afficher pour le service '{service:s}'",
"service_regenconf_dry_pending_applying": "Vérification des configurations en attentes qui pourraient être appliquées au le service '{service}' …",
"service_regenconf_failed": "Impossible de régénérer la configuration pour les services : {services}",
"service_regenconf_pending_applying": "Application des configurations en attentes pour le service '{service}' …",
@ -218,9 +218,9 @@
"service_unknown": "Le service '{service:s}' est inconnu",
"services_configured": "La configuration a été générée avec succès",
"show_diff": "Voici les différences :\n{diff:s}",
"ssowat_conf_generated": "La configuration de SSOwat a été générée",
"ssowat_conf_updated": "La configuration de SSOwat a été mise à jour",
"system_upgraded": "Le système a été mis à jour",
"ssowat_conf_generated": "La configuration de SSOwat générée",
"ssowat_conf_updated": "La configuration de SSOwat mise à jour",
"system_upgraded": "Système mis à jour",
"system_username_exists": "Ce nom dutilisateur existe déjà dans les utilisateurs système",
"unbackup_app": "Lapplication '{app:s}' ne sera pas sauvegardée",
"unexpected_error": "Une erreur inattendue est survenue : {error}",
@ -232,23 +232,23 @@
"upgrade_complete": "Mise à jour terminée",
"upgrading_packages": "Mise à jour des paquets en cours …",
"upnp_dev_not_found": "Aucun périphérique compatible UPnP na été trouvé",
"upnp_disabled": "UPnP a été désactivé",
"upnp_enabled": "UPnP a été activé",
"upnp_disabled": "UPnP désactivé",
"upnp_enabled": "UPnP activé",
"upnp_port_open_failed": "Impossible douvrir les ports UPnP",
"user_created": "Lutilisateur a été créé",
"user_creation_failed": "Impossible de créer lutilisateur",
"user_deleted": "Lutilisateur a été supprimé",
"user_deletion_failed": "Impossible de supprimer lutilisateur",
"user_created": "Lutilisateur créé",
"user_creation_failed": "Impossible de créer lutilisateur {user}: {error}",
"user_deleted": "Lutilisateur supprimé",
"user_deletion_failed": "Impossible de supprimer lutilisateur {user}: {error}",
"user_home_creation_failed": "Impossible de créer le dossier personnel de lutilisateur",
"user_info_failed": "Impossible de récupérer les informations de lutilisateur",
"user_unknown": "L'utilisateur {user:s} est inconnu",
"user_update_failed": "Impossible de modifier lutilisateur",
"user_update_failed": "Impossible de mettre à jour l'utilisateur {utilisateur}: {erreur}",
"user_updated": "Lutilisateur a été modifié",
"yunohost_already_installed": "YunoHost est déjà installé",
"yunohost_ca_creation_failed": "Impossible de créer lautorité de certification",
"yunohost_configured": "YunoHost a été configuré",
"yunohost_configured": "YunoHost est maintenant configuré",
"yunohost_installing": "L'installation de YunoHost est en cours …",
"yunohost_not_installed": "YunoHost nest pas ou pas correctement installé. Veuillez exécuter 'yunohost tools postinstall'",
"yunohost_not_installed": "YunoHost n'est pas correctement installé. Veuillez exécuter 'yunohost tools postinstall'",
"certmanager_attempt_to_replace_valid_cert": "Vous êtes en train de vouloir remplacer un certificat correct et valide pour le domaine {domain:s} ! (Utilisez --force pour contourner cela)",
"certmanager_domain_unknown": "Domaine {domain:s} inconnu",
"certmanager_domain_cert_not_selfsigned": "Le certificat du domaine {domain:s} nest pas auto-signé. Voulez-vous vraiment le remplacer ? (Utilisez --force pour cela)",
@ -259,17 +259,17 @@
"certmanager_error_no_A_record": "Aucun enregistrement DNS 'A' na été trouvé pour {domain:s}. Vous devez faire pointer votre nom de domaine vers votre machine pour être en mesure dinstaller un certificat Lets Encrypt ! (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces contrôles)",
"certmanager_domain_dns_ip_differs_from_public_ip": "Lenregistrement DNS 'A' du domaine {domain:s} est différent de ladresse IP de ce serveur. Si vous avez récemment modifié votre enregistrement 'A', veuillez attendre sa propagation (quelques vérificateur de propagation DNS sont disponibles en ligne). (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces contrôles)",
"certmanager_cannot_read_cert": "Quelque chose sest mal passé lors de la tentative douverture du certificat actuel pour le domaine {domain:s} (fichier : {file:s}), la cause est : {reason:s}",
"certmanager_cert_install_success_selfsigned": "Installation avec succès dun certificat auto-signé pour le domaine {domain:s} !",
"certmanager_cert_install_success": "Installation avec succès dun certificat Lets Encrypt pour le domaine {domain:s} !",
"certmanager_cert_renew_success": "Renouvellement avec succès dun certificat Lets Encrypt pour le domaine {domain:s} !",
"certmanager_cert_install_success_selfsigned": "Le certificat auto-signé est maintenant installé pour le domaine « {domain:s} »",
"certmanager_cert_install_success": "Le certificat Lets Encrypt est maintenant installé pour le domaine « {domain:s} »",
"certmanager_cert_renew_success": "Certificat Let's Encrypt renouvelé pour le domaine '{domain: s}'",
"certmanager_old_letsencrypt_app_detected": "\nYunoHost a détecté que lapplication « letsencrypt » est installé, ce qui est en conflit avec les nouvelles fonctionnalités de gestion intégrée de certificats dans YunoHost. Si vous souhaitez utiliser ces nouvelles fonctionnalités intégrées, veuillez lancer les commandes suivantes pour migrer votre installation :\n\n yunohost app remove letsencrypt\n yunohost domain cert-install\n\nN.B. : cela tentera de réinstaller les certificats de tous les domaines avec un certificat Let's Encrypt ou ceux auto-signés",
"certmanager_cert_signing_failed": "La signature du nouveau certificat a échoué",
"certmanager_cert_signing_failed": "Impossible de signer le nouveau certificat",
"certmanager_no_cert_file": "Impossible de lire le fichier du certificat pour le domaine {domain:s} (fichier : {file:s})",
"certmanager_conflicting_nginx_file": "Impossible de préparer le domaine pour le défi ACME : le fichier de configuration Nginx {filepath:s} est en conflit et doit être préalablement retiré",
"certmanager_conflicting_nginx_file": "Impossible de préparer le domaine pour le défi ACME : le fichier de configuration NGINX {filepath:s} est en conflit et doit être préalablement retiré",
"certmanager_hit_rate_limit": "Trop de certificats ont déjà été émis récemment pour ce même ensemble de domaines {domain:s}. Veuillez réessayer plus tard. Lisez https://letsencrypt.org/docs/rate-limits/ pour obtenir plus de détails sur les ratios et limitations",
"ldap_init_failed_to_create_admin": "Linitialisation de l'annuaire LDAP na pas réussi à créer lutilisateur admin",
"ssowat_persistent_conf_read_error": "Erreur lors de la lecture de la configuration persistante de SSOwat : {error:s}. Modifiez le fichier /etc/ssowat/conf.json.persistent pour réparer la syntaxe JSON",
"ssowat_persistent_conf_write_error": "Erreur lors de la sauvegarde de la configuration persistante de SSOwat : {error:s}. Modifiez le fichier /etc/ssowat/conf.json.persistent pour réparer la syntaxe JSON",
"ssowat_persistent_conf_read_error": "Impossible de lire la configuration persistante de SSOwat : {error:s}. Modifiez le fichier /etc/ssowat/conf.json.persistent pour réparer la syntaxe JSON",
"ssowat_persistent_conf_write_error": "Impossible de sauvegarder de la configuration persistante de SSOwat : {error:s}. Modifiez le fichier /etc/ssowat/conf.json.persistent pour réparer la syntaxe JSON",
"domain_cannot_remove_main": "Impossible de supprimer le domaine principal. Définissez d'abord un nouveau domaine principal",
"certmanager_self_ca_conf_file_not_found": "Le fichier de configuration pour lautorité du certificat auto-signé est introuvable (fichier : {file:s})",
"certmanager_unable_to_parse_self_CA_name": "Impossible danalyser le nom de lautorité du certificat auto-signé (fichier : {file:s})",
@ -280,14 +280,14 @@
"certmanager_domain_not_resolved_locally": "Le domaine {domain:s} ne peut être résolu depuis votre serveur YunoHost. Cela peut se produire si vous avez récemment modifié votre enregistrement DNS. Si c'est le cas, merci dattendre quelques heures quil se propage. Si le problème persiste, envisager dajouter {domain:s} au fichier /etc/hosts. (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces vérifications.)",
"certmanager_http_check_timeout": "Expiration du délai lorsque le serveur a essayé de se contacter lui-même via HTTP en utilisant l'adresse IP public {ip:s} du domaine {domain:s}. Vous rencontrez peut-être un problème dhairpinning ou alors le pare-feu/routeur en amont de votre serveur est mal configuré.",
"certmanager_couldnt_fetch_intermediate_cert": "Expiration du délai lors de la tentative de récupération du certificat intermédiaire depuis Lets Encrypt. Linstallation ou le renouvellement du certificat a été annulé. Veuillez réessayer plus tard.",
"appslist_retrieve_bad_format": "Le fichier récupéré pour la liste dapplications {appslist:s} nest pas valide",
"domain_hostname_failed": "Échec de lutilisation dun nouveau nom dhôte. Cela pourrait causer des soucis plus tard (mais ce nest pas sûr… peut-être que ça nen causera pas).",
"yunohost_ca_creation_success": "Lautorité de certification locale a été créée.",
"appslist_name_already_tracked": "Il y a déjà une liste dapplications enregistrée avec le nom {name:s}.",
"appslist_retrieve_bad_format": "Impossible de lire la liste des applications extraites '{appslist: s}'",
"domain_hostname_failed": "Échec de lutilisation dun nouveau nom dhôte. Cela pourrait causer des soucis plus tard (peut-être que ça nen causera pas).",
"yunohost_ca_creation_success": "Lautorité de certification locale créée.",
"appslist_name_already_tracked": "Une liste d'applications enregistrées portant le nom {name:s} existe déjà.",
"appslist_url_already_tracked": "Il y a déjà une liste dapplications enregistrée avec lURL {url:s}.",
"appslist_migrating": "Migration de la liste dapplications {appslist:s} …",
"appslist_could_not_migrate": "Impossible de migrer la liste {appslist:s} ! Impossible dexploiter lURL. Lancienne tâche programmée a été conservée dans {bkp_file:s}.",
"appslist_corrupted_json": "Impossible de charger la liste dapplications. Il semble que {filename:s} soit corrompu.",
"appslist_migrating": "Migration de la liste dapplications '{appslist:s}' …",
"appslist_could_not_migrate": "Impossible de migrer la liste '{appslist:s}' ! Impossible dexploiter lURL. Lancienne tâche programmée a été conservée dans {bkp_file:s}.",
"appslist_corrupted_json": "Impossible de charger la liste dapplications. Il semble que {filename:s} soit endommager.",
"app_already_installed_cant_change_url": "Cette application est déjà installée. LURL ne peut pas être changé simplement par cette fonction. Regardez si cela est disponible avec `app changeurl`.",
"app_change_no_change_url_script": "Lapplication {app_name:s} ne prend pas encore en charge le changement dURL, vous pourriez avoir besoin de la mettre à jour.",
"app_change_url_failed_nginx_reload": "Le redémarrage de Nginx a échoué. Voici la sortie de 'nginx -t' :\n{nginx_errors:s}",
@ -297,13 +297,13 @@
"app_location_unavailable": "Cette URL nest pas disponible ou est en conflit avec une application existante :\n{apps:s}",
"app_already_up_to_date": "{app:s} est déjà à jour",
"invalid_url_format": "Format dURL non valide",
"global_settings_bad_choice_for_enum": "Valeur du paramètre {setting:s} incorrecte. Reçu : {received_type:s}, mais les valeurs possibles sont : {expected_type:s}",
"global_settings_bad_choice_for_enum": "Valeur du paramètre {setting:s} incorrecte. Reçu : {choice:s}, mais les valeurs possibles sont : {available_choices:s}",
"global_settings_bad_type_for_setting": "Le type du paramètre {setting:s} est incorrect. Reçu {received_type:s} alors que {expected_type:s} était attendu",
"global_settings_cant_open_settings": "Échec de louverture du ficher de configurations car : {reason:s}",
"global_settings_cant_serialize_setings": "Échec de sérialisation des données de configurations, cause : {reason:s}",
"global_settings_cant_write_settings": "Échec décriture du fichier de configurations car : {reason:s}",
"global_settings_key_doesnt_exists": "La clef '{settings_key:s}' nexiste pas dans les configurations générales, vous pouvez voir toutes les clefs disponibles en saisissant 'yunohost settings list'",
"global_settings_reset_success": "Super ! Vos configurations précédentes ont été sauvegardées dans {path:s}",
"global_settings_reset_success": "Vos configurations précédentes ont été sauvegardées dans {path:s}",
"global_settings_setting_example_bool": "Exemple doption booléenne",
"global_settings_setting_example_int": "Exemple doption de type entier",
"global_settings_setting_example_string": "Exemple doption de type chaîne",
@ -312,32 +312,32 @@
"global_settings_unknown_setting_from_settings_file": "Clé inconnue dans les paramètres : '{setting_key:s}', rejet de cette clé et sauvegarde de celle-ci dans /etc/yunohost/unkown_settings.json",
"service_conf_new_managed_file": "Le fichier de configuration « {conf} » est désormais géré par le service {service}.",
"service_conf_file_kept_back": "Le fichier de configuration '{conf}' devait être supprimé par le service {service} mais a été conservé.",
"backup_abstract_method": "Cette méthode de sauvegarde na pas encore été implémentée",
"backup_applying_method_tar": "Création de larchive tar de la sauvegarde …",
"backup_abstract_method": "Cette méthode de sauvegarde reste à implémenter",
"backup_applying_method_tar": "Création de larchive TAR de la sauvegarde…",
"backup_applying_method_copy": "Copie de tous les fichiers à sauvegarder …",
"backup_applying_method_borg": "Envoi de tous les fichiers à sauvegarder dans le répertoire borg-backup…",
"backup_applying_method_custom": "Appel de la méthode de sauvegarde personnalisée '{method:s}' …",
"backup_archive_system_part_not_available": "La partie '{part:s}' du système nest pas disponible dans cette sauvegarde",
"backup_archive_mount_failed": "Le montage de larchive de sauvegarde a échoué",
"backup_archive_writing_error": "Impossible d'ajouter des fichiers '{source:s}' (nommés dans l'archive : '{dest:s}') à sauvegarder dans l'archive compressée '{archive:s}'",
"backup_ask_for_copying_if_needed": "Certains fichiers nont pas pu être préparés pour être sauvegardés en utilisant la méthode qui évite temporairement de gaspiller de lespace sur le système. Pour réaliser la sauvegarde, {size:s} Mo doivent être temporairement utilisés. Acceptez-vous ?",
"backup_ask_for_copying_if_needed": "Voulez-vous effectuer la sauvegarde en utilisant {taille:s} 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_borg_not_implemented": "La méthode de sauvegarde Borg nest pas encore implémentée",
"backup_cant_mount_uncompress_archive": "Impossible de monter en lecture seule le dossier de larchive décompressée",
"backup_copying_to_organize_the_archive": "Copie de {size:s} Mo pour organiser larchive",
"backup_csv_creation_failed": "Impossible de créer le fichier CSV nécessaire aux opérations futures de restauration",
"backup_csv_creation_failed": "Impossible de créer le fichier CSV nécessaire à la restauration",
"backup_csv_addition_failed": "Impossible dajouter des fichiers à sauvegarder dans le fichier CSV",
"backup_custom_need_mount_error": "Échec de la méthode de sauvegarde personnalisée à létape 'need_mount'",
"backup_custom_backup_error": "Échec de la méthode de sauvegarde personnalisée à létape 'backup'",
"backup_custom_mount_error": "Échec de la méthode de sauvegarde personnalisée à létape 'mount'",
"backup_no_uncompress_archive_dir": "Le dossier de larchive décompressée nexiste pas",
"backup_method_tar_finished": "Larchive tar de la sauvegarde a été créée",
"backup_no_uncompress_archive_dir": "Ce dossier darchive décompressée nexiste pas",
"backup_method_tar_finished": "Larchive TAR de la sauvegarde a été créée",
"backup_method_copy_finished": "La copie de la sauvegarde est terminée",
"backup_method_borg_finished": "La sauvegarde dans Borg est terminée",
"backup_method_custom_finished": "La méthode de sauvegarde personnalisée '{method:s}' est terminée",
"backup_system_part_failed": "Impossible de sauvegarder la partie '{part:s}' du système",
"backup_unable_to_organize_files": "Impossible dorganiser les fichiers dans larchive avec la méthode rapide",
"backup_unable_to_organize_files": "Impossible dutiliser la méthode rapide pour organiser les fichiers dans larchive",
"backup_with_no_backup_script_for_app": "Lapplication {app:s} na pas de script de sauvegarde. Ignorer.",
"backup_with_no_restore_script_for_app": "Lapplication {app:s} na pas de script de restauration, vous ne pourrez pas restaurer automatiquement la sauvegarde de cette application.",
"backup_with_no_restore_script_for_app": "Lapplication « {app:s} » na pas de script de restauration, vous ne pourrez pas restaurer automatiquement la sauvegarde de cette application.",
"global_settings_cant_serialize_settings": "Échec de la sérialisation des données de paramétrage car : {reason:s}",
"restore_removing_tmp_dir_failed": "Impossible de sauvegarder un ancien dossier temporaire",
"restore_extracting": "Extraction des fichiers nécessaires depuis larchive …",
@ -350,35 +350,35 @@
"domain_dyndns_dynette_is_unreachable": "Impossible de contacter la dynette YunoHost. Soit YunoHost nest pas correctement connecté à internet, soit le serveur de dynette est en panne. Erreur : {error}",
"migrations_backward": "Migration en arrière.",
"migrations_bad_value_for_target": "Nombre invalide pour le paramètre target, les numéros de migration sont 0 ou {}",
"migrations_cant_reach_migration_file": "Impossible daccéder aux fichiers de migrations avec le chemin %s",
"migrations_cant_reach_migration_file": "Impossible d'accéder aux fichiers de migration via le chemin '%s'",
"migrations_current_target": "La cible de migration est {}",
"migrations_error_failed_to_load_migration": "ERREUR : échec du chargement de migration {number} {name}",
"migrations_forward": "Migration en avant",
"migrations_loading_migration": "Chargement de la migration {number} {name} …",
"migrations_migration_has_failed": "La migration {number} {name} a échoué avec lexception {exception} : annulation",
"migrations_loading_migration": "Chargement de la migration {id} …",
"migrations_migration_has_failed": "La migration {id} a échoué avec lexception {exception} : annulation",
"migrations_no_migrations_to_run": "Aucune migration à lancer",
"migrations_show_currently_running_migration": "Application de la migration {number} {name} …",
"migrations_show_last_migration": "La dernière migration appliquée est {}",
"migrations_skip_migration": "Ignorer et passer la migration {number} {name}…",
"migrations_skip_migration": "Ignorer et passer la migration {id}…",
"server_shutdown": "Le serveur va éteindre",
"server_shutdown_confirm": "Le serveur va être éteint immédiatement, le voulez-vous vraiment ? [{answers:s}]",
"server_reboot": "Le serveur va redémarrer",
"server_reboot_confirm": "Le serveur va redémarrer immédiatement, le voulez-vous vraiment ? [{answers:s}]",
"app_upgrade_some_app_failed": "Impossible de mettre à jour certaines applications",
"app_upgrade_some_app_failed": "Certaines applications nont pas été mises à jour",
"ask_path": "Chemin",
"dyndns_could_not_check_provide": "Impossible de vérifier si {provider:s} peut fournir {domain:s}.",
"dyndns_domain_not_provided": "Le fournisseur DynDNS {provider:s} ne peut pas fournir le domaine {domain:s}.",
"app_make_default_location_already_used": "Impossible de configurer lapplication '{app}' par défaut pour le domaine {domain} car il est déjà utilisé par l'application '{other_app}'",
"app_make_default_location_already_used": "Impossible de configurer lapplication '{app}' par défaut pour le domaine '{domain}' car il est déjà utilisé par l'application '{other_app}'",
"app_upgrade_app_name": "Mise à jour de lapplication {app} …",
"backup_output_symlink_dir_broken": "Vous avez un lien symbolique cassé à la place de votre dossier darchives « {path:s} ». Vous pourriez avoir une configuration personnalisée pour sauvegarder vos données sur un autre système de fichiers, dans ce cas vous avez probablement oublié de monter ou de connecter votre disque dur ou votre clé USB.",
"migrate_tsig_end": "La migration à hmac-sha512 est terminée",
"backup_output_symlink_dir_broken": "Votre répertoire d'archivage '{path:s}' est un lien symbolique brisé. Peut-être avez-vous oublié de re/monter ou de brancher le support de stockage sur lequel il pointe.",
"migrate_tsig_end": "La migration à HMAC-SHA-512 est terminée",
"migrate_tsig_failed": "La migration du domaine DynDNS {domain} à hmac-sha512 a échoué. Annulation des modifications. Erreur : {error_code} - {error}",
"migrate_tsig_start": "Lalgorithme de génération des clefs nest pas suffisamment sécurisé pour la signature TSIG du domaine '{domain}', lancement de la migration vers hmac-sha512 qui est plus sécurisé",
"migrate_tsig_wait": "Attendre 3 minutes pour que le serveur DynDNS prenne en compte la nouvelle clef …",
"migrate_tsig_start": "Lalgorithme de génération des clefs nest pas suffisamment sécurisé pour la signature TSIG du domaine '{domain}', lancement de la migration vers HMAC-SHA-512 qui est plus sécurisé",
"migrate_tsig_wait": "Attendre trois minutes pour que le serveur DynDNS prenne en compte la nouvelle clef …",
"migrate_tsig_wait_2": "2 minutes …",
"migrate_tsig_wait_3": "1 minute …",
"migrate_tsig_wait_4": "30 secondes …",
"migrate_tsig_not_needed": "Il ne semble pas que vous utilisez un domaine DynDNS, donc aucune migration nest nécessaire !",
"migrate_tsig_not_needed": "Il ne semble pas que vous utilisez un domaine DynDNS, donc aucune migration nest nécessaire.",
"app_checkurl_is_deprecated": "Packagers /!\\ 'app checkurl' est obsolète ! Utilisez 'app register-url' en remplacement !",
"migration_description_0001_change_cert_group_to_sslcert": "Changement des permissions de groupe des certificats de « metronome » à « ssl-cert »",
"migration_description_0002_migrate_to_tsig_sha256": "Amélioration de la sécurité de DynDNS TSIG en utilisant SHA512 au lieu de MD5",
@ -393,37 +393,37 @@
"migration_0003_not_jessie": "La distribution Debian actuelle nest pas Jessie !",
"migration_0003_system_not_fully_up_to_date": "Votre système nest pas complètement à jour. Veuillez mener une mise à jour classique avant de lancer à migration à Stretch.",
"migration_0003_still_on_jessie_after_main_upgrade": "Quelque chose sest mal passé pendant la mise à niveau principale : le système est toujours sur Debian Jessie !? Pour investiguer sur le problème, veuillez regarder les journaux {log}:s …",
"migration_0003_general_warning": "Veuillez noter que cette migration est une opération délicate. Si léquipe YunoHost a fait de son mieux pour la relire et la tester, la migration pourrait tout de même casser des parties de votre système ou de vos applications.\n\nEn conséquence, nous vous recommandons :\n - de lancer une sauvegarde de vos données ou applications critiques. Plus dinformations sur https://yunohost.org/backup ;\n - dêtre patient après avoir lancé la migration : selon votre connexion internet et matériel, cela pourrait prendre jusquà quelques heures pour que tout soit à niveau.\n\nEn outre, le port SMTP utilisé par les clients de messagerie externes comme (Thunderbird ou K9-Mail) a été changé de 465 (SSL/TLS) à 587 (STARTTLS). Lancien port 465 sera automatiquement fermé et le nouveau port 587 sera ouvert dans le pare-feu. Vous et vos utilisateurs *devront* adapter la configuration de vos clients de messagerie en conséquence !",
"migration_0003_general_warning": "Veuillez noter que cette migration est une opération délicate. Si léquipe YunoHost a fait de son mieux pour la relire et la tester, la migration pourrait tout de même casser des parties de votre système ou de vos applications.\n\nEn conséquence, nous vous recommandons :\n - de lancer une sauvegarde de vos données ou applications critiques. Plus dinformations sur https://yunohost.org/backup ;\n - dêtre patient après avoir lancé la migration : selon votre connexion internet et matériel, cela pourrait prendre jusquà quelques heures pour que tout soit à niveau.\n\nEn outre, le port SMTP utilisé par les clients de messagerie externes comme (Thunderbird ou K9-Mail) a été changé de 465 (SSL/TLS) à 587 (STARTTLS). Lancien port 465 sera automatiquement fermé et le nouveau port 587 sera ouvert dans le pare-feu. Vous et vos utilisateurs *devront* adapter la configuration de vos clients de messagerie en conséquence.",
"migration_0003_problematic_apps_warning": "Veuillez noter que des applications possiblement problématiques ont été détectées. Il semble quelles naient pas été installées depuis une liste dapplication ou quelles ne soit pas marquées comme « fonctionnelles ». En conséquence, nous ne pouvons pas garantir quelles fonctionneront après la mise à niveau : {problematic_apps}",
"migration_0003_modified_files": "Veuillez noter que les fichiers suivants ont été détectés comme modifiés manuellement et pourraient être écrasés à la fin de la mise à niveau : {manually_modified_files}",
"migrations_list_conflict_pending_done": "Vous ne pouvez pas utiliser --previous et --done simultanément.",
"migrations_to_be_ran_manually": "La migration {number} {name} doit être lancée manuellement. Veuillez aller dans Outils > Migrations dans linterface admin, ou lancer `yunohost tools migrations migrate`.",
"migrations_need_to_accept_disclaimer": "Pour lancer la migration {number} {name}, vous devez accepter cette clause de non-responsabilité :\n---\n{disclaimer}\n---\nSi vous acceptez de lancer la migration, veuillez relancer la commande avec loption --accept-disclaimer.",
"service_description_avahi-daemon": "permet datteindre votre serveur via yunohost.local sur votre réseau local",
"service_description_dnsmasq": "gère la résolution des noms de domaine (DNS)",
"service_description_dovecot": "permet aux clients de messagerie daccéder/récupérer les courriels (via IMAP et POP3)",
"service_description_fail2ban": "protège contre les attaques brute-force et autres types dattaques venant dInternet",
"service_description_glances": "surveille les informations système de votre serveur",
"service_description_metronome": "gère les comptes de messagerie instantanée XMPP",
"service_description_mysql": "stocke les données des applications (bases de données SQL)",
"service_description_nginx": "sert ou permet laccès à tous les sites web hébergés sur votre serveur",
"service_description_nslcd": "gère la connexion en ligne de commande des utilisateurs YunoHost",
"migrations_to_be_ran_manually": "La migration {id} doit être lancée manuellement. Veuillez aller dans Outils > Migrations dans linterface admin, ou lancer `yunohost tools migrations migrate`.",
"migrations_need_to_accept_disclaimer": "Pour lancer la migration {id}, vous devez accepter cette clause de non-responsabilité :\n---\n{disclaimer}\n---\nSi vous acceptez de lancer la migration, veuillez relancer la commande avec loption --accept-disclaimer.",
"service_description_avahi-daemon": "Vous permet datteindre votre serveur en utilisant «yunohost.local» sur votre réseau local",
"service_description_dnsmasq": "Gère la résolution des noms de domaine (DNS)",
"service_description_dovecot": "Permet aux clients de messagerie daccéder/récupérer les courriels (via IMAP et POP3)",
"service_description_fail2ban": "Protège contre les attaques brute-force et autres types dattaques venant dInternet",
"service_description_glances": "Surveille les info système de votre serveur",
"service_description_metronome": "Gère les comptes de messagerie instantanée XMPP",
"service_description_mysql": "Stocke les données des applications (bases de données SQL)",
"service_description_nginx": "Sert ou permet laccès à tous les sites web hébergés sur votre serveur",
"service_description_nslcd": "Gère la connexion en ligne de commande des utilisateurs YunoHost",
"service_description_php5-fpm": "exécute des applications écrites en PHP avec nginx",
"service_description_postfix": "utilisé pour envoyer et recevoir des courriels",
"service_description_redis-server": "une base de données spécialisée utilisée pour laccès rapide aux données, les files dattentes et la communication entre les programmes",
"service_description_rmilter": "vérifie divers paramètres dans les courriels",
"service_description_rspamd": "filtre le pourriel, et dautres fonctionnalités liées au courriel",
"service_description_slapd": "stocke les utilisateurs, domaines et leurs informations liées",
"service_description_ssh": "vous permet de vous connecter à distance à votre serveur via un terminal (protocole SSH)",
"service_description_yunohost-api": "permet les interactions entre linterface web de YunoHost et le système",
"service_description_yunohost-firewall": "gère l'ouverture et la fermeture des ports de connexion aux services",
"service_description_postfix": "Utilisé pour envoyer et recevoir des courriels",
"service_description_redis-server": "Une base de données spécialisée utilisée pour laccès rapide aux données, les files dattentes et la communication entre les programmes",
"service_description_rmilter": "Vérifie divers paramètres dans les courriels",
"service_description_rspamd": "Filtre le pourriel, et dautres fonctionnalités liées au courriel",
"service_description_slapd": "Stocke les utilisateurs, domaines et leurs informations liées",
"service_description_ssh": "Vous permet de vous connecter à distance à votre serveur via un terminal (protocole SSH)",
"service_description_yunohost-api": "Permet les interactions entre linterface web de YunoHost et le système",
"service_description_yunohost-firewall": "Gère l'ouverture et la fermeture des ports de connexion aux services",
"experimental_feature": "Attention : cette fonctionnalité est expérimentale et ne doit pas être considérée comme stable, vous ne devriez pas lutiliser à 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_category_404": "Le journal de la catégorie '{category}' nexiste pas",
"log_link_to_log": "Journal historisé 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 historisé de cette opération '{desc}', utilisez la commande 'yunohost log display {name}'",
"log_link_to_failed_log": "Lopération '{desc}' a échouée ! Pour avoir de laide, merci <a href=\"#/tools/logs/{name}\"> de fournir le journal historisé complet de lopération en cliquant ici</a>",
"backup_php5_to_php7_migration_may_fail": "Impossible de convertir votre archive pour prendre en charge php7, vos applications php pourraient ne pas être restaurées (reason: {error:s})",
"log_link_to_failed_log": "Lopération '{desc}' a échouée ! Pour avoir de laide, merci <a href=\"#/tools/logs/{name}\"> cliqué ici</a> pour avoir de l'aide",
"backup_php5_to_php7_migration_may_fail": "Impossible de convertir votre archive pour prendre en charge PHP 7, vous pourriez ne plus pouvoir restaurer vos applications PHP (cause : {error:s})",
"log_help_to_get_failed_log": "Lopération '{desc}' a échouée ! Pour avoir de laide, merci de partager le journal historisé de cette opération en utilisant la commande 'yunohost log display {name} --share'",
"log_does_exists": "Il nexiste pas de journal historisé de lopération ayant pour nom '{log}', utiliser 'yunohost log list pour voir tous les fichiers de journaux historisés disponibles'",
"log_operation_unit_unclosed_properly": "Lopération ne sest pas terminée correctement",
@ -462,18 +462,18 @@
"log_tools_shutdown": "Éteindre votre serveur",
"log_tools_reboot": "Redémarrer votre serveur",
"mail_unavailable": "Cette adresse de courriel est réservée et doit être automatiquement attribuée au tout premier utilisateur",
"migration_description_0004_php5_to_php7_pools": "Reconfiguration des groupes PHP pour utiliser PHP 7 au lieu de PHP 5",
"migration_description_0004_php5_to_php7_pools": "Reconfigurez les groupes PHP pour utiliser PHP 7 au lieu de PHP 5",
"migration_description_0005_postgresql_9p4_to_9p6": "Migration des bases de données de PostgreSQL 9.4 vers PostgreSQL 9.6",
"migration_0005_postgresql_94_not_installed": "PostgreSQL na pas été installé sur votre système. Rien à faire !",
"migration_0005_postgresql_96_not_installed": "PostgreSQL 9.4 a été trouvé et installé, mais pas PostgreSQL 9.6 !? Quelque chose détrange a dû arriver à votre système… :(",
"migration_0005_not_enough_space": "Il ny a pas assez despace libre de disponible sur {path} pour lancer maintenant la migration :(.",
"migration_0005_not_enough_space": "Laissez suffisamment d'espace disponible dans {chemin} pour exécuter la migration.",
"recommend_to_add_first_user": "La post-installation est terminée mais YunoHost a besoin dau moins un utilisateur pour fonctionner correctement. Vous devez en ajouter un en utilisant la commande 'yunohost user create $nomdutilisateur' ou bien via linterface dadministration web.",
"service_description_php7.0-fpm": "exécute des applications écrites en PHP avec Nginx",
"service_description_php7.0-fpm": "Exécute des applications écrites en PHP avec NGINX",
"users_available": "Liste des utilisateurs disponibles :",
"good_practices_about_admin_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe dadministration. Le mot de passe doit comporter au moins 8 caractères bien quil soit recommandé dutiliser un mot de passe plus long (cest-à-dire une phrase secrète) et/ou dutiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
"good_practices_about_user_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe utilisateur. Le mot de passe doit comporter au moins 8 caractères - bien quil soit recommandé dutiliser un mot de passe plus long (cest-à-dire une phrase secrète) et/ou dutiliser différents types de caractères tels que : majuscules, minuscules, chiffres et caractères spéciaux.",
"migration_description_0006_sync_admin_and_root_passwords": "Synchroniser les mots de passe admin et root",
"migration_0006_disclaimer": "YunoHost sattendra désormais à ce que les mots de passe admin et root soient synchronisés. En exécutant cette migration, votre mot de passe root sera remplacé par le mot de passe administrateur.",
"migration_0006_disclaimer": "YunoHost s'attend maintenant à ce que les mots de passe administrateur et racine soient synchronisés. Cette migration remplace votre mot de passe root par le mot de passe administrateur.",
"migration_0006_done": "Votre mot de passe root a été remplacé par celui de votre adminitrateur.",
"password_listed": "Ce mot de passe est l'un des mots de passe les plus utilisés dans le monde. Veuillez choisir quelque chose d'un peu plus singulier.",
"password_too_simple_1": "Le mot de passe doit comporter au moins 8 caractères",
@ -481,11 +481,11 @@
"password_too_simple_3": "Le mot de passe doit comporter au moins 8 caractères et contenir des chiffres, des majuscules, des minuscules et des caractères spéciaux",
"password_too_simple_4": "Le mot de passe doit comporter au moins 12 caractères et contenir des chiffres, des majuscules, des minuscules et des caractères spéciaux",
"root_password_desynchronized": "Le mot de passe administrateur a été changé, mais YunoHost na pas pu le propager au mot de passe root !",
"aborting": "Opération annulée.",
"app_not_upgraded": "Les applications suivantes n'ont pas été mises à jour : {apps}",
"aborting": "Annulation.",
"app_not_upgraded": "Lapplication {failed_app} na pas été mise à jour et par conséquence les applications suivantes nont pas été mises à jour : {apps}",
"app_start_install": "Installation de l'application {app} …",
"app_start_remove": "Suppression de l'application {app} …",
"app_start_backup": "Collecte des fichiers devant être sauvegardés pour {app} …",
"app_start_backup": "Collecte des fichiers devant être sauvegardés pour l'application {app} …",
"app_start_restore": "Restauration de l'application {app} …",
"app_upgrade_several_apps": "Les applications suivantes seront mises à jour : {apps}",
"ask_new_domain": "Nouveau domaine",
@ -493,8 +493,8 @@
"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 …",
"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:s}] ",
"confirm_app_install_danger": "AVERTISSEMENT ! Cette application est encore expérimentale (explicitement, elle ne fonctionne pas) et risque de casser votre système ! Vous ne devriez probablement PAS l'installer sans savoir ce que vous faites. Êtes-vous prêt à prendre ce risque ? [{answers:s}] ",
"confirm_app_install_thirdparty": "AVERTISSEMENT ! L'installation d'applications tierces peut compromettre l'intégrité et la sécurité de votre système. Vous ne devriez probablement PAS l'installer si vous ne savez pas ce que vous faites. Êtes-vous prêt à prendre ce risque ? [{answers:s}] ",
"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: s}'",
"confirm_app_install_thirdparty": "DANGER! Cette application ne fait pas partie du catalogue d'applications de Yunohost. L'installation d'applications tierces peut compromettre l'intégrité et la sécurité de votre système. 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:s}'",
"dpkg_is_broken": "Vous ne pouvez pas faire ça maintenant car dpkg/apt (le gestionnaire de paquets du système) semble avoir laissé des choses non configurées. Vous pouvez essayer de résoudre ce problème en vous connectant via SSH et en exécutant `sudo dpkg --configure -a'.",
"dyndns_could_not_check_available": "Impossible de vérifier si {domain:s} est disponible chez {provider:s}.",
"file_does_not_exist": "Le fichier dont le chemin est {path:s} n'existe pas.",
@ -504,14 +504,14 @@
"hook_json_return_error": "Échec de la lecture au retour du script {path:s}. Erreur : {msg:s}. Contenu brut : {raw_content}",
"migration_description_0007_ssh_conf_managed_by_yunohost_step1": "La configuration SSH sera gérée par YunoHost (étape 1, automatique)",
"migration_description_0008_ssh_conf_managed_by_yunohost_step2": "La configuration SSH sera gérée par YunoHost (étape 2, manuelle)",
"migration_0007_cancelled": "YunoHost n'a pas réussi à améliorer la façon dont est gérée votre configuration SSH.",
"migration_0007_cancelled": "Impossible d'améliorer la gestion de votre configuration SSH.",
"migration_0007_cannot_restart": "SSH ne peut pas être redémarré après avoir essayé d'annuler la migration numéro 6.",
"migration_0008_general_disclaimer": "Pour améliorer la sécurité de votre serveur, il est recommandé de laisser YunoHost gérer la configuration SSH. Votre configuration SSH actuelle diffère de la configuration recommandée. Si vous laissez YunoHost la reconfigurer, la façon dont vous vous connectez à votre serveur via SSH changera comme suit :",
"migration_0008_port": " - vous devrez vous connecter en utilisant le port 22 au lieu de votre actuel port SSH personnalisé. N'hésitez pas à le reconfigurer ;",
"migration_0008_root": " - vous ne pourrez pas vous connecter en tant que root via SSH. Au lieu de cela, vous devrez utiliser l'utilisateur admin ;",
"migration_0008_dsa": " - la clé DSA sera désactivée. Par conséquent, il se peut que vous ayez besoin d'invalider un avertissement effrayant de votre client SSH afin de revérifier l'empreinte de votre serveur ;",
"migration_0008_warning": "Si vous comprenez ces avertissements et que vous acceptez de laisser YunoHost remplacer votre configuration actuelle, exécutez la migration. Sinon, vous pouvez également passer la migration, bien que cela ne soit pas recommandé.",
"migration_0008_no_warning": "Aucun risque majeur n'a été identifié concernant l'écrasement de votre configuration SSH - mais nous ne pouvons pas en être absolument sûrs ;) ! Si vous acceptez de laisser YunoHost remplacer votre configuration actuelle, exécutez la migration. Sinon, vous pouvez également passer la migration, bien que cela ne soit pas recommandé.",
"migration_0008_port": "- Vous devrez vous connecter en utilisant le port 22 au lieu de votre actuel port SSH personnalisé. N'hésitez pas à le reconfigurer ;",
"migration_0008_root": "- Vous ne pourrez pas vous connecter en tant que root via SSH. Au lieu de cela, vous devrez utiliser l'utilisateur admin ;",
"migration_0008_dsa": "- La clé DSA sera désactivée. Par conséquent, il se peut que vous ayez besoin d'invalider un avertissement effrayant de votre client SSH afin de revérifier l'empreinte de votre serveur ;",
"migration_0008_warning": "Si vous comprenez ces avertissements et souhaitez que YunoHost écrase votre configuration actuelle, exécutez la migration. Sinon, vous pouvez également ignorer la migration, bien que cela ne soit pas recommandé.",
"migration_0008_no_warning": "Remplacer votre configuration SSH devrait être sûr, bien que cela ne puisse être promis! Exécutez la migration pour la remplacer. Sinon, vous pouvez également ignorer la migration, bien que cela ne soit pas recommandé.",
"migrations_success": "Migration {number} {name} réussie !",
"pattern_password_app": "Désolé, les mots de passe ne doivent pas contenir les caractères suivants : {forbidden_chars}",
"root_password_replaced_by_admin_password": "Votre mot de passe root a été remplacé par votre mot de passe administrateur.",
@ -523,8 +523,8 @@
"service_reload_or_restart_failed": "Impossible de recharger ou de redémarrer le service '{service:s}'\n\nJournaux historisés récents de ce service : {logs:s}",
"service_reloaded_or_restarted": "Le service '{service:s}' a été rechargé ou redémarré",
"this_action_broke_dpkg": "Cette action a laissé des paquets non configurés par dpkg/apt (les gestionnaires de paquets système). Vous pouvez essayer de résoudre ce problème en vous connectant via SSH et en exécutant `sudo dpkg --configure -a`.",
"app_action_cannot_be_ran_because_required_services_down": "Cette application requiert certains services qui sont actuellement arrêtés. Avant de continuer, vous devriez essayer de redémarrer les services suivants (et éventuellement rechercher pourquoi ils sont arrêtés) : {services}",
"admin_password_too_long": "Choisissez un mot de passe plus court que 127 caractères",
"app_action_cannot_be_ran_because_required_services_down": "Ces services requis doivent être en cours d'exécution pour exécuter cette action: {services}. Essayez de les redémarrer pour continuer (et éventuellement rechercher pourquoi ils sont en panne).",
"admin_password_too_long": "Veuillez choisir un mot de passe de moins de 127 caractères",
"log_regen_conf": "Régénérer les configurations du système '{}'",
"migration_0009_not_needed": "Cette migration semble avoir déjà été jouée ? On l'ignore.",
"regenconf_file_backed_up": "Le fichier de configuration '{conf}' a été sauvegardé sous '{backup}'",
@ -549,36 +549,36 @@
"regenconf_failed": "Impossible de régénérer la configuration pour la ou les catégorie(s) : '{categories}'",
"regenconf_pending_applying": "Applique la configuration en attente pour la catégorie '{category}' …",
"service_regen_conf_is_deprecated": "'yunohost service regen-conf' est obsolète ! Veuillez plutôt utiliser 'yunohost tools regen-conf' à la place.",
"tools_upgrade_at_least_one": "Veuillez spécifier --apps OU --system",
"tools_upgrade_at_least_one": "Veuillez spécifier '--apps' OU '--system'",
"tools_upgrade_cant_both": "Impossible de mettre à niveau le système et les applications en même temps",
"tools_upgrade_cant_hold_critical_packages": "Impossibilité de maintenir les paquets critiques...",
"tools_upgrade_regular_packages": "Mise à jour des paquets du système (non liés a YunoHost) ...",
"tools_upgrade_cant_hold_critical_packages": "Impossibilité de maintenir les paquets critiques",
"tools_upgrade_regular_packages": "Mise à jour des paquets du système (non liés a YunoHost) ",
"tools_upgrade_regular_packages_failed": "Impossible de mettre à jour les paquets suivants : {packages_list}",
"tools_upgrade_special_packages": "Mise à jour des paquets 'spécifiques' (liés a YunoHost) ...",
"tools_upgrade_special_packages": "Mise à jour des paquets 'spécifiques' (liés a YunoHost) ",
"tools_upgrade_special_packages_completed": "La mise à jour des paquets de YunoHost est finie!\nPressez [Entrée] pour revenir à la ligne de commande",
"updating_app_lists": "Récupération des mises à jour des applications disponibles…",
"dpkg_lock_not_available": "Cette commande ne peut être lancée maintenant car il semblerai qu'un autre programme utilise déjà le verrou dpkg du gestionnaire de paquets du système",
"tools_upgrade_cant_unhold_critical_packages": "Impossible de dé-marquer les paquets critiques ...",
"tools_upgrade_special_packages_explanation": "Cette opération prendra fin mais la mise à jour spécifique continuera en arrière-plan. Veuillez ne pas lancer d'autre action sur votre serveur dans les 10 prochaines minutes (en fonction de la vitesse de votre matériel). Une fois que c'est fait, vous devrez peut-être vous reconnecter sur le panel d'administration web. Le journal de la mise à jour sera disponible dans Outils > Log (dans le panel d'administration web) ou dans la liste des journaux YunoHost (en ligne de commande).",
"dpkg_lock_not_available": "Cette commande ne peut être exécutée actuellement car un autre programme semble utiliser le verrou de dpkg (gestionnaire de paquets)",
"tools_upgrade_cant_unhold_critical_packages": "Impossible de conserver les paquets critiques…",
"tools_upgrade_special_packages_explanation": "Cette action se terminera, mais la mise à niveau spéciale réelle continuera en arrière-plan. Veuillez ne pas lancer dautres actions sur votre serveur au cours des 10 prochaines minutes (en fonction de la vitesse du matériel). Une fois cela fait, vous devrez peut-être vous reconnecter à la page Webadmin. Le journal de mise à niveau sera disponible dans Outils → Journal (sur la page Webadmin) ou dans la \"liste des journaux yunohost\" (à partir de la ligne de commande).",
"update_apt_cache_failed": "Impossible de mettre à jour le cache APT (gestionnaire de paquets Debian). Voici un extrait du fichier sources.list qui pourrait vous aider à identifier les lignes problématiques :\n{sourceslist}",
"update_apt_cache_warning": "Des erreurs se sont produites lors de la mise à jour du cache APT (gestionnaire de paquets Debian). Voici un extrait des lignes du fichier sources.list qui pourrait vous aider à identifier les lignes problématiques :\n{sourceslist}",
"apps_permission_not_found": "Aucune permission trouvée pour les applications installées",
"apps_permission_restoration_failed": "L'autorisation '{permission:s}' pour la restauration de l'application {app:s} a échoué",
"backup_permission": "Autorisation de sauvegarde pour l'application {app:s}",
"backup_permission": "Permission de sauvegarde pour l'application {app:s}",
"edit_group_not_allowed": "Vous n'êtes pas autorisé à modifier le groupe {group:s}",
"error_when_removing_sftpuser_group": "Erreur en essayant de supprimer le groupe sftpusers",
"group_created": "Le groupe '{group}' a créé avec succès",
"group_deleted": "Le groupe '{group}' a été supprimé",
"error_when_removing_sftpuser_group": "Vous ne pouvez pas supprimer le groupe sftpusers",
"group_created": "Le groupe '{group}' a été créé",
"group_deleted": "Suppression du groupe '{group}'",
"group_deletion_not_allowed": "Le groupe {group:s} ne peut pas être supprimé manuellement.",
"group_info_failed": "L'information sur le groupe a échoué",
"group_unknown": "Le groupe {group:s} est inconnu",
"group_updated": "Le groupe '{group}' a été mis à jour",
"group_update_failed": "La mise à jour du groupe '{group}' a échoué",
"group_update_failed": "La mise à jour du groupe '{group}' a échoué : {error}",
"group_already_allowed": "Le groupe '{group:s}' a déjà la permission '{permission:s}' activée pour l'application '{app:s}'",
"group_already_disallowed": "Le groupe '{group:s}' a déjà la permission '{permission:s}' désactivée pour l'application '{app:s}'",
"group_name_already_exist": "Le groupe {name:s} existe déjà",
"group_creation_failed": "Échec de la création du groupe '{group}'",
"group_deletion_failed": "Échec de la suppression du groupe '{group}'",
"group_creation_failed": "Échec de la création du groupe '{group}': {error}",
"group_deletion_failed": "Échec de la suppression du groupe '{group}': {error}",
"edit_permission_with_group_all_users_not_allowed": "Vous n'êtes pas autorisé à modifier les permissions pour le groupe 'all_users', utilisez 'yunohost user permission clear APP' ou 'yunohost user permission add APP -u USER' à la place.",
"log_permission_add": "Ajouter l'autorisation '{}' pour l'application '{}'",
"log_permission_remove": "Supprimer l'autorisation '{}'",
@ -588,5 +588,81 @@
"log_user_group_update": "Mettre à jour '{}' pour le groupe",
"log_user_permission_add": "Mettre à jour l'autorisation pour '{}'",
"log_user_permission_remove": "Mettre à jour l'autorisation pour '{}'",
"mailbox_disabled": "La boîte aux lettres est désactivée pour l'utilisateur {user:s}"
"mailbox_disabled": "La boîte aux lettres est désactivée pour l'utilisateur {user:s}",
"app_action_broke_system": "Cette action semble avoir cassé des services important : {services}",
"apps_already_up_to_date": "Toutes les applications sont déjà à jour",
"app_upgrade_stopped": "La mise à niveau de toutes les applications s'est arrêtée pour éviter tout dommage, car une application n'a pas pu être mise à niveau.",
"migration_0011_create_group": "Créer un groupe pour chaque utilisateur…",
"migration_0011_done": "Migration terminée. Vous êtes maintenant en mesure de gérer des groupes d'utilisateurs.",
"migrations_must_provide_explicit_targets": "Vous devez fournir des cibles explicites lorsque vous utilisez '--skip' ou '--force-rerun'",
"migrations_no_such_migration": "Il n'y a pas de migration appelée '{id}'",
"migrations_pending_cant_rerun": "Ces migrations étant toujours en attente, vous ne pouvez pas les exécuter à nouveau: {ids}",
"migration_description_0012_postgresql_password_to_md5_authentication": "Forcer l'authentification PostgreSQL à utiliser MD5 pour les connexions locales",
"migrations_exclusive_options": "'auto', '--skip' et '--force-rerun' sont des options mutuellement exclusives.",
"migrations_not_pending_cant_skip": "Ces migrations ne sont pas en attente et ne peuvent donc pas être ignorées: {ids}",
"migration_0011_can_not_backup_before_migration": "La sauvegarde du système n'a pas pu être terminée avant l'échec de la migration. Erreur: {erreur:s}",
"migration_0011_migrate_permission": "Migration des autorisations des paramètres des applications vers LDAP…",
"migration_0011_migration_failed_trying_to_rollback": "Impossible de migrer… en essayant de restaurer le système.",
"migration_0011_rollback_success": "Système restauré.",
"migration_0011_update_LDAP_database": "Mise à jour de la base de données LDAP…",
"system_groupname_exists": "Le nom de groupe existe déjà dans le groupe du systèmes",
"tools_update_failed_to_app_fetchlist": "Impossible de mettre à jour les listes d'applications de YunoHost car: {error}",
"user_already_in_group": "L'utilisateur '{user:}' est déjà dans le groupe '{group: s}'",
"user_not_in_group": "L'utilisateur '{user: s}' ne fait pas partie du groupe {group: s}",
"migration_0011_backup_before_migration": "Création d'une sauvegarde des paramètres de la base de données LDAP et des applications avant la migration.",
"permission_not_found": "Autorisation '{permission:s}' introuvable",
"permission_name_not_valid": "Choisissez un nom d'autorisation autorisé pour '{permission: s}'",
"permission_update_failed": "Impossible de mettre à jour la permission '{permission}': {error}",
"permission_generated": "Base de données des autorisations mise à jour",
"permission_updated": "Permission '{permission:s}' mise à jour",
"permission_update_nothing_to_do": "Aucune autorisation pour mettre à jour",
"remove_main_permission_not_allowed": "Supprimer l'autorisation principale n'est pas autorisé",
"dyndns_provider_unreachable": "Impossible datteindre le fournisseur Dyndns {provider}: votre YunoHost nest pas correctement connecté à Internet ou le serveur Dynette est en panne.",
"migration_0011_update_LDAP_schema": "Mise à jour du schéma LDAP…",
"migrations_already_ran": "Ces migrations sont déjà effectuées: {ids}",
"migrations_dependencies_not_satisfied": "Exécutez ces migrations: '{dependencies_id}', avant migration {id}.",
"migrations_failed_to_load_migration": "Impossible de charger la migration {id}: {error}",
"migrations_running_forward": "Exécution de la migration {id}…",
"migrations_success_forward": "Migration {id} terminée",
"need_define_permission_before": "Redéfinissez l'autorisation à l'aide de 'yunohost user permission add -u USER' avant de supprimer un groupe autorisé",
"operation_interrupted": "L'opération a-t-elle été interrompue manuellement ?",
"permission_already_clear": "L'autorisation '{permission: s}' est déjà vide pour l'application {app: s}",
"permission_already_exist": "L'autorisation '{permission}' existe déjà",
"permission_created": "Permission '{permission:s}' créée",
"permission_creation_failed": "Impossible de créer l'autorisation '{permission}': {erreur}",
"permission_deleted": "Permission '{permission:s}' supprimée",
"permission_deletion_failed": "Impossible de supprimer la permission '{permission}': {error}",
"remove_user_of_group_not_allowed": "Vous n'êtes pas autorisé à supprimer l'utilisateur '{utilisateur: s}' dans le groupe '{groupe: s}'",
"migration_description_0011_setup_group_permission": "Configurer le groupe d'utilisateurs et configurer les autorisations pour les applications et les services",
"migration_0011_LDAP_config_dirty": "Il semble que vous ayez personnalisé votre configuration LDAP. Pour cette migration, la configuration LDAP doit être mise à jour.\nVous devez enregistrer votre configuration actuelle, réintialiser la configuration d'origine en exécutant 'yunohost tools regen-conf -f', puis réessayer la migration",
"migration_0011_LDAP_update_failed": "Impossible de mettre à jour LDAP. Erreur: {error: s}",
"group_already_exist": "Le groupe {group} existe déjà",
"group_already_exist_on_system": "Le groupe {group} existe déjà dans les groupes système",
"group_cannot_be_edited": "Le groupe {group} ne peut pas être édité manuellement.",
"group_cannot_be_deleted": "Le groupe {group} ne peut pas être supprimé manuellement.",
"group_user_already_in_group": "L'utilisateur {user} est déjà dans le groupe {group}",
"group_user_not_in_group": "L'utilisateur {user} n'est pas dans le groupe {group}",
"log_permission_create": "Créer permission '{}'",
"log_permission_delete": "supprimer permission '{}'",
"log_permission_urls": "Mettre à jour les URL liées à la permission '{}'",
"log_user_group_create": "Créer '{}' groupe",
"log_user_permission_update": "Mise à jour des accès pour la permission '{}'",
"log_user_permission_reset": "Réinitialiser la permission '{}'",
"migration_0011_failed_to_remove_stale_object": "Impossible de supprimer un objet périmé {dn}: {error}",
"permission_already_allowed": "Le groupe '{group}' a déjà l'autorisation '{permission}' activée",
"permission_already_disallowed": "Le groupe '{group}' a déjà l'autorisation '{permission}' désactivé '",
"permission_cannot_remove_main": "Supprimer une autorisation principale n'est pas autorisé",
"user_already_exists": "L'utilisateur '{user}' existe déjà",
"app_full_domain_unavailable": "Désolé, cette application doit être installée sur un domaine qui lui est propre, mais d'autres applications sont déjà installées sur le domaine '{domain}'. Vous pouvez utiliser un sous-domaine dédié à cette application à la place.",
"group_cannot_edit_all_users": "Le groupe 'all_users' ne peut pas être édité manuellement. C'est un groupe spécial destiné à contenir tous les utilisateurs enregistrés dans YunoHost",
"group_cannot_edit_visitors": "Le groupe 'visiteurs' ne peut pas être édité manuellement. C'est un groupe spécial représentant les visiteurs anonymes",
"group_cannot_edit_primary_group": "Le groupe '{group}' ne peut pas être édité manuellement. C'est le groupe principal destiné à ne contenir qu'un utilisateur spécifique.",
"log_permission_url": "Mise à jour de l'URL associée à l'autorisation '{}'",
"migration_0011_slapd_config_will_be_overwritten": "Il semble que vous ayez modifié manuellement la configuration de slapd. Pour cette migration critique, YunoHost doit forcer la mise à jour de la configuration de slapd. Les fichiers originaux seront sauvegardés dans {conf_backup_folder}.",
"permission_already_up_to_date": "L'autorisation n'a pas été mise à jour car les demandes d'ajout/suppression correspondent déjà à l'état actuel.",
"permission_currently_allowed_for_visitors": "Cette autorisation est actuellement accordée aux visiteurs en plus d'autres groupes. Vous voudrez probablement supprimer l'autorisation \"visiteurs\" ou supprimer les autres groupes auxquels il est actuellement attribué.",
"permission_currently_allowed_for_all_users": "Cette autorisation est actuellement accordée à tous les utilisateurs en plus des autres groupes. Vous voudrez probablement soit supprimer l'autorisation 'all_users', soit supprimer les autres groupes auxquels il est actuellement autorisé.",
"app_install_failed": "Impossible d'installer {app}: {error}",
"app_install_script_failed": "Une erreur est survenue dans le script d'installation de l'application",
"permission_require_account": "Permission {permission} n'a de sens que pour les utilisateurs ayant un compte et ne peut donc pas être activé pour les visiteurs."
}

View file

@ -1 +1,169 @@
{}
{
"aborting": "Avbryter…",
"admin_password": "Administrasjonspassord",
"admin_password_change_failed": "Kan ikke endre passord",
"admin_password_changed": "Administrasjonspassord endret",
"admin_password_too_long": "Velg et passord kortere enn 127 tegn",
"app_already_installed": "{app:s} er allerede installert",
"app_already_up_to_date": "{app:s} er allerede oppdatert",
"app_argument_invalid": "Velg en gydlig verdi for argumentet '{name:s}': {error:s}",
"app_argument_required": "Argumentet '{name:s}' er påkrevd",
"diagnosis_no_apps": "Inget program installert",
"app_id_invalid": "Ugyldig program-ID",
"dyndns_cron_remove_failed": "Kunne ikke fjerne cron-jobb for DynDNS: {error}",
"dyndns_key_not_found": "Fant ikke DNS-nøkkel for domenet",
"app_not_correctly_installed": "{app:s} ser ikke ut til å ha blitt installert på riktig måte",
"dyndns_provider_unreachable": "Kunne ikke nå DynDNS-tilbyder {provider}: Enten har du ikke satt opp din YunoHost rett, dynette-tjeneren er nede, eller du mangler nett.",
"app_not_properly_removed": "{app:s} har ikke blitt fjernet på riktig måte",
"app_package_need_update": "Programmet {app}-pakken må oppdateres for å holde følge med YunoHost sine endringer",
"app_removed": "{app:s} fjernet",
"app_requirements_checking": "Sjekker påkrevde pakker for {app:s}…",
"app_requirements_failed": "Noen krav er ikke oppfylt for {app:s}: {error}",
"app_start_install": "Installerer programmet '{app}'…",
"action_invalid": "Ugyldig handling '{action:s}'",
"app_start_restore": "Gjenoppretter programmet '{app}'…",
"backup_created": "Sikkerhetskopi opprettet",
"backup_archive_name_exists": "En sikkerhetskopi med dette navnet finnes allerede.",
"backup_archive_name_unknown": "Ukjent lokalt sikkerhetskopiarkiv ved navn '{name:s}'",
"already_up_to_date": "Ingenting å gjøre. Alt er oppdatert.",
"backup_method_copy_finished": "Sikkerhetskopi fullført",
"backup_method_tar_finished": "TAR-sikkerhetskopiarkiv opprettet",
"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.",
"diagnosis_monitor_disk_error": "Kunne ikke holde oppsyn med disker: {error}",
"diagnosis_monitor_system_error": "Kunne ikke holde oppsyn med systemet: {error}",
"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:s}",
"domains_available": "Tilgjengelige domener:",
"done": "Ferdig",
"downloading": "Laster ned…",
"dyndns_could_not_check_provide": "Kunne ikke sjekke om {provider:s} kan tilby {domain:s}.",
"dyndns_could_not_check_available": "Kunne ikke sjekke om {domain:s} er tilgjengelig på {provider:s}.",
"log_app_removeaccess": "Fjern tilgang til '{}'",
"license_undefined": "udefinert",
"mail_domain_unknown": "Ukjent e-postadresse for domenet '{domain:s}'",
"migrate_tsig_wait_2": "2 min…",
"log_remove_on_failed_restore": "Fjern '{}' etter mislykket gjenoppretting fra sikkerhetskopiarkiv",
"log_letsencrypt_cert_install": "Installer et Let's Encrypt-sertifikat på '{}'-domenet",
"log_permission_update": "Oppdater tilgang '{}' for programmet '{}'",
"log_letsencrypt_cert_renew": "Forny '{}'-Let's Encrypt-sertifikat",
"log_user_update": "Oppdater brukerinfo for '{}'",
"mail_alias_remove_failed": "Kunne ikke fjerne e-postaliaset '{mail:s}'",
"app_action_broke_system": "Denne handlingen ser ut til å ha knekt disse viktige tjenestene: {services}",
"app_argument_choice_invalid": "Bruk én av disse valgene '{choices:s}' for argumentet '{name:s}'",
"app_extraction_failed": "Kunne ikke pakke ut installasjonsfilene",
"app_incompatible": "Programmet {app} er ikke kompatibelt med din YunoHost-versjon",
"app_install_files_invalid": "Disse filene kan ikke installeres",
"app_location_already_used": "Programmet '{app}' er allerede installert i ({path})",
"ask_path": "Sti",
"backup_abstract_method": "Denne sikkerhetskopimetoden er ikke implementert enda",
"backup_actually_backuping": "Oppretter sikkerhetskopiarkiv fra innsamlede filer…",
"backup_app_failed": "Kunne ikke sikkerhetskopiere programmet '{app:s}'",
"backup_applying_method_tar": "Lager TAR-sikkerhetskopiarkiv…",
"backup_archive_app_not_found": "Fant ikke programmet '{app:s}' i sikkerhetskopiarkivet",
"backup_archive_open_failed": "Kunne ikke åpne sikkerhetskopiarkivet",
"app_start_remove": "Fjerner programmet '{app}'…",
"app_start_backup": "Samler inn filer for sikkerhetskopiering for {app}…",
"backup_applying_method_copy": "Kopier alle filer til sikkerhetskopi…",
"backup_borg_not_implemented": "Borg-sikkerhetskopimetoden er ikke implementert enda",
"backup_creation_failed": "Kunne ikke opprette sikkerhetskopiarkiv",
"backup_couldnt_bind": "Kunne ikke binde {src:s} til {dest:s}.",
"backup_csv_addition_failed": "Kunne ikke legge til filer for sikkerhetskopi inn i CSV-filen",
"backup_deleted": "Sikkerhetskopi slettet",
"backup_no_uncompress_archive_dir": "Det finnes ingen slik utpakket arkivmappe",
"backup_delete_error": "Kunne ikke slette '{path:s}'",
"certmanager_domain_unknown": "Ukjent domene '{domain:s}'",
"certmanager_cert_signing_failed": "Kunne ikke signere det nye sertifikatet",
"diagnosis_debian_version_error": "Kunne ikke hente Debian-versjon: {error}",
"diagnosis_kernel_version_error": "Kunne ikke hente kjerneversjon: {error}",
"error_when_removing_sftpuser_group": "Kunne ikke fjerne sftpusers-gruppen",
"executing_command": "Kjører kommendoen '{command:s}'…",
"executing_script": "Kjører skriptet '{script:s}'…",
"extracting": "Pakker ut…",
"edit_group_not_allowed": "Du tillates ikke å redigere gruppen {group:s}",
"log_domain_add": "Legg til '{}'-domenet i systemoppsett",
"log_domain_remove": "Fjern '{}'-domenet fra systemoppsett",
"log_dyndns_subscribe": "Abonner på YunoHost-underdomenet '{}'",
"log_dyndns_update": "Oppdater IP-adressen tilknyttet ditt YunoHost-underdomene '{}'",
"migrate_tsig_wait_3": "1 min…",
"migrate_tsig_wait_4": "30 sekunder…",
"apps_permission_restoration_failed": "Innvilg tilgangen '{permission:s}' for å gjenopprette {app:}",
"apps_permission_not_found": "Fant ingen tilgang for de installerte programmene",
"backup_invalid_archive": "Dette er ikke et sikkerhetskopiarkiv",
"backup_nothings_done": "Ingenting å lagre",
"backup_method_borg_finished": "Sikkerhetskopi inn i Borg fullført",
"field_invalid": "Ugyldig felt '{:s}'",
"firewall_reloaded": "Brannmur gjeninnlastet",
"log_app_removelist": "Fjern en programliste",
"log_app_change_url": "Endre nettadresse for '{}'-programmet",
"log_app_install": "Installer '{}'-programmet",
"log_app_remove": "Fjern '{}'-programmet",
"log_app_upgrade": "Oppgrader '{}'-programmet",
"log_app_makedefault": "Gjør '{}' til forvalgt program",
"log_available_on_yunopaste": "Denne loggen er nå tilgjengelig via {url}",
"log_tools_maindomain": "Gjør '{}' til hoveddomene",
"log_tools_shutdown": "Slå av tjeneren din",
"log_tools_reboot": "Utfør omstart av tjeneren din",
"apps_already_up_to_date": "Alle programmer allerede oppdatert",
"backup_mount_archive_for_restore": "Forbereder arkiv for gjenopprettelse…",
"backup_copying_to_organize_the_archive": "Kopierer {size:s} MB for å organisere arkivet",
"domain_cannot_remove_main": "Kan ikke fjerne hoveddomene. Sett et først",
"domain_cert_gen_failed": "Kunne ikke opprette sertifikat",
"domain_created": "Domene opprettet",
"domain_creation_failed": "Kunne ikke opprette domene",
"domain_dyndns_root_unknown": "Ukjent DynDNS-rotdomene",
"domain_unknown": "Ukjent domene",
"dyndns_cron_installed": "Opprettet cron-jobb for DynDNS",
"dyndns_cron_removed": "Fjernet cron-jobb for DynDNS",
"dyndns_ip_update_failed": "Kunne ikke oppdatere IP-adresse til DynDNS",
"dyndns_ip_updated": "Oppdaterte din IP på DynDNS",
"dyndns_key_generating": "Oppretter DNS-nøkkel… Dette kan ta en stund.",
"dyndns_no_domain_registered": "Inget domene registrert med DynDNS",
"dyndns_registered": "DynDNS-domene registrert",
"global_settings_setting_security_password_admin_strength": "Admin-passordets styrke",
"dyndns_registration_failed": "Kunne ikke registrere DynDNS-domene: {error:s}",
"global_settings_setting_security_password_user_strength": "Brukerpassordets styrke",
"log_app_fetchlist": "Legg til en programliste",
"log_backup_restore_app": "Gjenopprett '{}' fra sikkerhetskopiarkiv",
"log_remove_on_failed_install": "Fjern '{}' etter mislykket installasjon",
"log_permission_add": "Legg til '{}'-tilgangen for programmet '{}'",
"log_permission_remove": "Fjern tilgangen '{}'",
"log_selfsigned_cert_install": "Installer selvsignert sertifikat på '{}'-domenet",
"log_user_delete": "Slett '{}' bruker",
"log_user_group_add": "Legg til '{}' gruppe",
"log_user_group_delete": "Slett '{}' gruppe",
"log_user_group_update": "Oppdater '{}' gruppe",
"log_user_permission_add": "Oppdater '{}' tilgang",
"log_user_permission_remove": "Oppdater '{}' tilgang",
"ldap_init_failed_to_create_admin": "LDAP-igangsettelse kunne ikke opprette admin-bruker",
"ldap_initialized": "LDAP-igangsatt",
"maindomain_changed": "Hoveddomenet er nå endret",
"migration_description_0003_migrate_to_stretch": "Oppgrader systemet til Debian Stretch og YunoHost 3.0",
"app_unknown": "Ukjent program",
"app_upgrade_app_name": "Oppgraderer {app}…",
"app_upgrade_failed": "Kunne ikke oppgradere {app:s}",
"app_upgrade_some_app_failed": "Noen programmer kunne ikke oppgraderes",
"app_upgraded": "{app:s} oppgradert",
"ask_email": "E-postadresse",
"ask_firstname": "Fornavn",
"ask_lastname": "Etternavn",
"ask_list_to_remove": "Liste å fjerne",
"ask_main_domain": "Hoveddomene",
"ask_new_admin_password": "Nytt administrasjonspassord",
"app_upgrade_several_apps": "Følgende programmer vil oppgraderes: {apps}",
"appslist_removed": "{appslist:s}-programliste fjernet",
"appslist_url_already_tracked": "Dette er allerede en registrert programliste med nettadressen {url:s}.",
"ask_current_admin_password": "Nåværende administrasjonspassord",
"appslist_unknown": "Programlisten {appslist:s} er ukjent.",
"ask_new_domain": "Nytt domene",
"ask_new_path": "Ny sti",
"ask_password": "Passord",
"domain_deleted": "Domene slettet",
"domain_deletion_failed": "Kunne ikke slette domene",
"domain_dyndns_already_subscribed": "Du har allerede abonnement på et DynDNS-domene",
"log_category_404": "Loggkategorien '{category}' finnes ikke",
"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 display {name}'",
"log_app_clearaccess": "Fjern all tilgang til '{}'",
"log_user_create": "Legg til '{}' bruker"
}

View file

@ -198,7 +198,7 @@
"migrations_current_target": "La cibla de migracion est {}",
"migrations_error_failed_to_load_migration": "ERROR: fracàs del cargament de la migracion {number} {name}",
"migrations_list_conflict_pending_done": "Podètz pas utilizar --previous e --done a lencòp.",
"migrations_loading_migration": "Cargament de la migracion{number} {name}…",
"migrations_loading_migration": "Cargament de la migracion {id}…",
"migrations_no_migrations_to_run": "Cap de migracion de lançar",
"migrations_show_currently_running_migration": "Realizacion de la migracion {number} {name}…",
"migrations_show_last_migration": "La darrièra migracion realizada es {}",
@ -376,10 +376,10 @@
"migration_0003_general_warning": "Notatz quaquesta migracion es una operacion delicata. Encara que la còla YunoHost aguèsse fach çò melhor per la tornar legir e provar, la migracion poiriá copar de parts del sistèma o de las aplicacions.\n\nEn consequéncia, vos recomandam:\n· · · · - de lançar una salvagarda de vòstras donadas o aplicacions criticas. Mai dinformacions a https://yunohost.org/backup ;\n· · · · - dèsser pacient aprèp aver lançat la migracion: segon vòstra connexion Internet e material, pòt trigar qualques oras per que tot siá mes al nivèl.\n\nEn mai, lo pòrt per SMTP, utilizat pels clients de corrièls extèrns (coma Thunderbird o K9-Mail per exemple) foguèt cambiat de 465 (SSL/TLS) per 587 (STARTTLS). Lancian pòrt 465 serà automaticament tampat e lo nòu pòrt 587 serà dobèrt dins lo parafuòc. Vosautres e vòstres utilizaires *auretz* dadaptar la configuracion de vòstre client de corrièl segon aqueles cambiaments!",
"migration_0003_problematic_apps_warning": "Notatz que las aplicacions seguentas, saique problematicas, son estadas desactivadas. Semblan daver estadas installadas duna lista daplicacions o que son pas marcadas coma «working ». En consequéncia, podèm pas assegurar que tendràn de foncionar aprèp la mesa a nivèl: {problematic_apps}",
"migrations_bad_value_for_target": "Nombre invalid pel paramètre «target », los numèros de migracion son 0 o {}",
"migrations_migration_has_failed": "La migracion {number} {name} a pas capitat amb lexcepcion {exception}, anullacion",
"migrations_skip_migration": "Passatge de la migracion {number} {name}…",
"migrations_to_be_ran_manually": "La migracion {number} {name} deu èsser lançada manualament. Mercés danar a Aisinas > Migracion dins linterfàcia admin, o lançar «yunohost tools migrations migrate ».",
"migrations_need_to_accept_disclaimer": "Per lançar la migracion {number} {name} , avètz dacceptar aquesta clausa de non-responsabilitat:\n---\n{disclaimer}\n---\nSacceptatz de lançar la migracion, mercés de tornar executar la comanda amb lopcion accept-disclaimer.",
"migrations_migration_has_failed": "La migracion {id} a pas capitat, abandon. Error : {exception}",
"migrations_skip_migration": "Passatge de la migracion {id}…",
"migrations_to_be_ran_manually": "La migracion {id} deu èsser lançada manualament. Mercés danar a Aisinas > Migracion dins linterfàcia admin, o lançar «yunohost tools migrations migrate ».",
"migrations_need_to_accept_disclaimer": "Per lançar la migracion {id} , avètz dacceptar aquesta clausa de non-responsabilitat:\n---\n{disclaimer}\n---\nSacceptatz de lançar la migracion, mercés de tornar executar la comanda amb lopcion accept-disclaimer.",
"monitor_disabled": "La supervision del servidor es desactivada",
"monitor_enabled": "La supervision del servidor es activada",
"mysql_db_initialized": "La basa de donadas MySQL es estada inicializada",
@ -453,7 +453,7 @@
"migration_0005_postgresql_94_not_installed": "Postgresql es pas installat sul sistèma. Pas res de far!",
"migration_0005_postgresql_96_not_installed": "Avèm trobat que Postgresql 9.4 es installat, mas cap de version de Postgresql 9.6 pas trobada!? Quicòm destranh a degut arribar a vòstre sistèma :( …",
"migration_0005_not_enough_space": "I a pas pro despaci disponible sus {path} per lançar la migracion daquela passa :(.",
"recommend_to_add_first_user": "La post installacion es acabada, mas YunoHost fa besonh dalmens un utilizaire per foncionar coma cal. Vos cal najustar un en utilizant la comanda «yunohost user create $username » o ben linterfàcia dadministracion.",
"recommend_to_add_first_user": "La post installacion es acabada, mas YunoHost fa besonh dalmens un utilizaire per foncionar coma cal. Vos cal najustar un en utilizant la comanda «yunohost user create <username&gt;&#39; » o ben linterfàcia dadministracion.",
"service_description_php7.0-fpm": "executa daplicacions escrichas en PHP amb nginx",
"users_available": "Lista dels utilizaires disponibles:",
"good_practices_about_admin_password": "Sètz per definir un nòu senhal per ladministracion. Lo senhal deu almens conténer 8 caractèrs - encara que siá de bon far dutilizar un senhal mai long quaquò (ex. una passafrasa) e/o dutilizar mantun tipes de caractèrs (majuscula, minuscula, nombre e caractèrs especials).",
@ -468,7 +468,7 @@
"password_too_simple_4": "Lo senhal deu conténer almens 12 caractèrs, de nombre, majusculas, minisculas e caractèrs specials",
"root_password_desynchronized": "Lo senhal de ladministrator es estat cambiat, mas YunoHost a pas pogut lespandir al senhal root!",
"aborting": "Interrupcion.",
"app_not_upgraded": "Las aplicacions seguentas son pas estadas actualizadas: {apps}",
"app_not_upgraded": "Laplicacion « {failed_app} » a pas reüssit a sactualizar e coma consequéncia las mesas a jorn de las aplicacions seguentas son estadas anulladas : {apps}",
"app_start_install": "Installacion de laplicacion {app}…",
"app_start_remove": "Supression de laplicacion {app}…",
"app_start_backup": "Recuperacion dels fichièrs de salvagardar per {app}…",
@ -606,5 +606,11 @@
"migration_0011_LDAP_config_dirty": "Sembla quavètz modificat manualament la configuracion LDAP. Per far aquesta migracion cal actualizar la configuracion LDAP.\nSalvagardatz la configuracion actuala, reïnicializatz la configuracion originala amb la comanda « yunohost tools regen-conf -f » e tornatz ensajar la migracion",
"need_define_permission_before": "Vos cal tornar definir las permission en utilizant « yunohost user permission add -u USER » abans de suprimir un grop permés",
"permission_already_clear": "La permission « {permission:s} » ja levada per laplicacion {app:s}",
"migration_description_0012_postgresql_password_to_md5_authentication": "Forçar lautentificacion postgresql a utilizar md5 per las connexions localas"
"migration_description_0012_postgresql_password_to_md5_authentication": "Forçar lautentificacion postgresql a utilizar md5 per las connexions localas",
"migrations_success_forward": "Migracion {id} corrèctament realizada !",
"migrations_running_forward": "Execucion de la migracion {id}…",
"migrations_must_provide_explicit_targets": "Devètz fornir una cibla explicita quand utilizatz using --skip o --force-rerun",
"migrations_exclusive_options": "--auto, --skip, e --force-rerun son las opcions exclusivas.",
"migrations_failed_to_load_migration": "Cargament impossible de la migracion {id} : {error}",
"migrations_already_ran": "Aquelas migracions sexecutèron ja : {ids}"
}

View file

@ -72,7 +72,7 @@
"ldap_initialized": "LDAP inicializada com êxito",
"license_undefined": "indefinido",
"mail_alias_remove_failed": "Não foi possível remover a etiqueta de correio '{mail:s}'",
"mail_domain_unknown": "Domínio de endereço de correio desconhecido '{domain:s}'",
"mail_domain_unknown": "Domínio de endereço de correio '{domain:s}' inválido. Por favor, usa um domínio administrado per esse servidor.",
"mail_forward_remove_failed": "Não foi possível remover o reencaminhamento de correio '{mail:s}'",
"maindomain_change_failed": "Incapaz alterar o domínio raiz",
"maindomain_changed": "Domínio raiz alterado com êxito",

View file

@ -1 +1,3 @@
{}
{
"password_too_simple_1": "Lösenordet måste bestå av minst åtta tecken"
}

View file

@ -41,7 +41,7 @@ from datetime import datetime
from moulinette import msignals, m18n, msettings
from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import read_json, read_toml
from moulinette.utils.filesystem import read_json, read_toml, read_yaml, write_to_json
from yunohost.service import service_log, service_status, _run_service_command
from yunohost.utils import packages
@ -406,10 +406,10 @@ def app_map(app=None, raw=False, user=None):
"""
from yunohost.permission import user_permission_list
from yunohost.utils.ldap import _get_ldap_interface
apps = []
result = {}
permissions = user_permission_list(full=True)["permissions"]
if app is not None:
if not _is_installed(app):
@ -427,27 +427,85 @@ def app_map(app=None, raw=False, user=None):
if 'path' not in app_settings:
# we assume that an app that doesn't have a path doesn't have an HTTP api
continue
# This 'no_sso' settings sound redundant to not having $path defined ....
# At least from what I can see, all apps using it don't have a path defined ...
if 'no_sso' in app_settings: # I don't think we need to check for the value here
continue
if user is not None:
ldap = _get_ldap_interface()
if not ldap.search(base='ou=permission,dc=yunohost,dc=org',
filter='(&(objectclass=permissionYnh)(cn=main.%s)(inheritPermission=uid=%s,ou=users,dc=yunohost,dc=org))' % (app_id, user),
attrs=['cn']):
# Users must at least have access to the main permission to have access to extra permissions
if user:
if not app_id + ".main" in permissions:
logger.warning("Uhoh, no main permission was found for app %s ... sounds like an app was only partially removed due to another bug :/" % app_id)
continue
main_perm = permissions[app_id + ".main"]
if user not in main_perm["corresponding_users"] and "visitors" not in main_perm["allowed"]:
continue
domain = app_settings['domain']
path = app_settings['path']
path = app_settings['path'].rstrip('/')
label = app_settings['label']
if raw:
if domain not in result:
result[domain] = {}
result[domain][path] = {
'label': app_settings['label'],
'id': app_settings['id']
}
else:
result[domain + path] = app_settings['label']
def _sanitized_absolute_url(perm_url):
# Nominal case : url is relative to the app's path
if perm_url.startswith("/"):
perm_domain = domain
perm_path = path + perm_url.rstrip("/")
# Otherwise, the urls starts with a domain name, like domain.tld/foo/bar
# We want perm_domain = domain.tld and perm_path = "/foo/bar"
else:
perm_domain, perm_path = perm_url.split("/", 1)
perm_path = "/" + perm_path.rstrip("/")
return perm_domain, perm_path
this_app_perms = {p: i for p, i in permissions.items() if p.startswith(app_id + ".") and i["url"]}
for perm_name, perm_info in this_app_perms.items():
# If we're building the map for a specific user, check the user
# actually is allowed for this specific perm
if user and user not in perm_info["corresponding_users"] and "visitors" not in perm_info["allowed"]:
continue
if perm_info["url"].startswith("re:"):
# Here, we have an issue if the chosen url is a regex, because
# the url we want to add to the dict is going to be turned into
# a clickable link (or analyzed by other parts of yunohost
# code...). To put it otherwise : in the current code of ssowat,
# you can't give access a user to a regex.
#
# Instead, as drafted by Josue, we could rework the ssowat logic
# about how routes and their permissions are defined. So for example,
# have a dict of
# { "/route1": ["visitors", "user1", "user2", ...], # Public route
# "/route2_with_a_regex$": ["user1", "user2"], # Private route
# "/route3": None, # Skipped route idk
# }
# then each time a user try to request and url, we only keep the
# longest matching rule and check the user is allowed etc...
#
# The challenge with this is (beside actually implementing it)
# is that it creates a whole new mechanism that ultimately
# replace all the existing logic about
# protected/unprotected/skipped uris and regexes and we gotta
# handle / migrate all the legacy stuff somehow if we don't
# want to end up with a total mess in the future idk
logger.error("Permission %s can't be added to the SSOwat configuration because it doesn't support regexes so far..." % perm_name)
continue
perm_domain, perm_path = _sanitized_absolute_url(perm_info["url"])
if perm_name.endswith(".main"):
perm_label = label
else:
# e.g. if perm_name is wordpress.admin, we want "Blog (Admin)" (where Blog is the label of this app)
perm_label = "%s (%s)" % (label, perm_name.rsplit(".")[-1].replace("_", " ").title())
if raw:
if domain not in result:
result[perm_domain] = {}
result[perm_domain][perm_path] = {
'label': perm_label,
'id': app_id
}
else:
result[perm_domain + perm_path] = perm_label
return result
@ -465,14 +523,13 @@ def app_change_url(operation_logger, app, domain, path):
"""
from yunohost.hook import hook_exec, hook_callback
from yunohost.domain import _normalize_domain_path, _get_conflicting_apps
from yunohost.permission import permission_update
installed = _is_installed(app)
if not installed:
raise YunohostError('app_not_installed', app=app, all_apps=_get_all_installed_apps_id())
if not os.path.exists(os.path.join(APPS_SETTING_PATH, app, "scripts", "change_url")):
raise YunohostError("app_change_no_change_url_script", app_name=app)
raise YunohostError("app_change_url_no_script", app_name=app)
old_domain = app_setting(app, "domain")
old_path = app_setting(app, "path")
@ -555,7 +612,7 @@ def app_change_url(operation_logger, app, domain, path):
app_setting(app, 'domain', value=domain)
app_setting(app, 'path', value=path)
permission_update(app, permission="main", add_url=[domain+path], remove_url=[old_domain+old_path], sync_perm=True)
app_ssowatconf()
# avoid common mistakes
if _run_service_command("reload", "nginx") is False:
@ -590,7 +647,7 @@ def app_upgrade(app=[], url=None, file=None):
try:
app_list()
except YunohostError:
raise YunohostError('app_no_upgrade')
raise YunohostError('apps_already_up_to_date')
not_upgraded_apps = []
@ -611,7 +668,7 @@ def app_upgrade(app=[], url=None, file=None):
raise YunohostError('app_not_installed', app=app, all_apps=_get_all_installed_apps_id())
if len(apps) == 0:
raise YunohostError('app_no_upgrade')
raise YunohostError('apps_already_up_to_date')
if len(apps) > 1:
logger.info(m18n.n("app_upgrade_several_apps", apps=", ".join(apps)))
@ -765,11 +822,9 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu
force -- Do not ask for confirmation when installing experimental / low-quality apps
"""
from yunohost.utils.ldap import _get_ldap_interface
from yunohost.hook import hook_add, hook_remove, hook_exec, hook_callback
from yunohost.log import OperationLogger
from yunohost.permission import permission_add, permission_update, permission_remove, permission_sync_to_user
ldap = _get_ldap_interface()
from yunohost.permission import user_permission_list, permission_create, permission_url, permission_delete, permission_sync_to_user, user_permission_update
# Fetch or extract sources
if not os.path.exists(INSTALL_TMP):
@ -789,20 +844,41 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu
if confirm is None or force or msettings.get('interface') == 'api':
return
answer = msignals.prompt(m18n.n('confirm_app_install_' + confirm,
answers='Y/N'))
if answer.upper() != "Y":
raise YunohostError("aborting")
if confirm in ["danger", "thirdparty"]:
answer = msignals.prompt(m18n.n('confirm_app_install_' + confirm,
answers='Yes, I understand'),
color="red")
if answer != "Yes, I understand":
raise YunohostError("aborting")
else:
answer = msignals.prompt(m18n.n('confirm_app_install_' + confirm,
answers='Y/N'),
color="yellow")
if answer.upper() != "Y":
raise YunohostError("aborting")
raw_app_list = app_list(raw=True)
if app in raw_app_list or ('@' in app) or ('http://' in app) or ('https://' in app):
# If we got an app name directly (e.g. just "wordpress"), we gonna test this name
if app in raw_app_list:
state = raw_app_list[app].get("state", "notworking")
level = raw_app_list[app].get("level", None)
app_name_to_test = app
# If we got an url like "https://github.com/foo/bar_ynh, we want to
# extract "bar" and test if we know this app
elif ('http://' in app) or ('https://' in app):
app_name_to_test = app.strip("/").split("/")[-1].replace("_ynh","")
if app_name_to_test in raw_app_list:
state = raw_app_list[app_name_to_test].get("state", "notworking")
level = raw_app_list[app_name_to_test].get("level", None)
confirm = "danger"
if state in ["working", "validated"]:
if isinstance(level, int) and level >= 3:
if isinstance(level, int) and level >= 5:
confirm = None
elif isinstance(level, int) and level > 0:
confirm = "warning"
@ -847,6 +923,9 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu
args_list = [ value[0] for value in args_odict.values() ]
args_list.append(app_instance_name)
# Validate domain / path availability for webapps
_validate_and_normalize_webpath(manifest, args_odict, extracted_app_folder)
# Prepare env. var. to pass to script
env_dict = _make_environment_dict(args_odict)
env_dict["YNH_APP_ID"] = app_id
@ -902,83 +981,106 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu
if os.path.exists(os.path.join(extracted_app_folder, file_to_copy)):
os.system('cp -R %s/%s %s' % (extracted_app_folder, file_to_copy, app_setting_path))
# Create permission before the install (useful if the install script redefine the permission)
# Note that sync_perm is disabled to avoid triggering a whole bunch of code and messages
# can't be sure that we don't have one case when it's needed
permission_add(app=app_instance_name, permission="main", sync_perm=False)
# Initialize the main permission for the app
# After the install, if apps don't have a domain and path defined, the default url '/' is removed from the permission
permission_create(app_instance_name+".main", url="/", allowed=["all_users"])
# Execute the app install script
install_retcode = 1
install_failed = True
try:
install_retcode = hook_exec(
os.path.join(extracted_app_folder, 'scripts/install'),
args=args_list, env=env_dict
)[0]
# "Common" app install failure : the script failed and returned exit code != 0
install_failed = True if install_retcode != 0 else False
if install_failed:
error = m18n.n('app_install_script_failed')
logger.exception(m18n.n("app_install_failed", app=app_id, error=error))
failure_message_with_debug_instructions = operation_logger.error(error)
# Script got manually interrupted ... N.B. : KeyboardInterrupt does not inherit from Exception
except (KeyboardInterrupt, EOFError):
install_retcode = -1
except Exception:
error = m18n.n('operation_interrupted')
logger.exception(m18n.n("app_install_failed", app=app_id, error=error))
failure_message_with_debug_instructions = operation_logger.error(error)
# Something wrong happened in Yunohost's code (most probably hook_exec)
except Exception as e:
import traceback
logger.exception(m18n.n('unexpected_error', error=u"\n" + traceback.format_exc()))
error = m18n.n('unexpected_error', error=u"\n" + traceback.format_exc())
logger.exception(m18n.n("app_install_failed", app=app_id, error=error))
failure_message_with_debug_instructions = operation_logger.error(error)
finally:
# Whatever happened (install success or failure) we check if it broke the system
# and warn the user about it
try:
broke_the_system = False
_assert_system_is_sane_for_app(manifest, "post")
except Exception as e:
broke_the_system = True
error_msg = operation_logger.error(str(e))
logger.exception(m18n.n("app_install_failed", app=app_id, error=str(e)))
failure_message_with_debug_instructions = operation_logger.error(str(e))
if install_retcode != 0:
error_msg = operation_logger.error(m18n.n('unexpected_error', error='shell command return code: %s' % install_retcode))
# If the install failed or broke the system, we remove it
if install_failed or broke_the_system:
if install_retcode != 0 or broke_the_system:
if not no_remove_on_failure:
# Setup environment for remove script
env_dict_remove = {}
env_dict_remove["YNH_APP_ID"] = app_id
env_dict_remove["YNH_APP_INSTANCE_NAME"] = app_instance_name
env_dict_remove["YNH_APP_INSTANCE_NUMBER"] = str(instance_number)
# This option is meant for packagers to debug their apps more easily
if no_remove_on_failure:
raise YunohostError("The installation of %s failed, but was not cleaned up as requested by --no-remove-on-failure." % app_id, raw_msg=True)
else:
logger.warning(m18n.n("app_remove_after_failed_install"))
# Execute remove script
operation_logger_remove = OperationLogger('remove_on_failed_install',
[('app', app_instance_name)],
env=env_dict_remove)
operation_logger_remove.start()
# Setup environment for remove script
env_dict_remove = {}
env_dict_remove["YNH_APP_ID"] = app_id
env_dict_remove["YNH_APP_INSTANCE_NAME"] = app_instance_name
env_dict_remove["YNH_APP_INSTANCE_NUMBER"] = str(instance_number)
# Execute remove script
operation_logger_remove = OperationLogger('remove_on_failed_install',
[('app', app_instance_name)],
env=env_dict_remove)
operation_logger_remove.start()
# Try to remove the app
try:
remove_retcode = hook_exec(
os.path.join(extracted_app_folder, 'scripts/remove'),
args=[app_instance_name], env=env_dict_remove
)[0]
# Remove all permission in LDAP
result = ldap.search(base='ou=permission,dc=yunohost,dc=org',
filter='(&(objectclass=permissionYnh)(cn=*.%s))' % app_instance_name, attrs=['cn'])
permission_list = [p['cn'][0] for p in result]
for l in permission_list:
permission_remove(app_instance_name, l.split('.')[0], force=True)
# Here again, calling hook_exec could fail miserably, or get
# manually interrupted (by mistake or because script was stuck)
# In that case we still want to proceed with the rest of the
# removal (permissions, /etc/yunohost/apps/{app} ...)
except (KeyboardInterrupt, EOFError, Exception):
remove_retcode = -1
import traceback
logger.exception(m18n.n('unexpected_error', error=u"\n" + traceback.format_exc()))
if remove_retcode != 0:
msg = m18n.n('app_not_properly_removed',
app=app_instance_name)
logger.warning(msg)
operation_logger_remove.error(msg)
# Remove all permission in LDAP
for permission_name in user_permission_list()["permissions"].keys():
if permission_name.startswith(app_instance_name+"."):
permission_delete(permission_name, force=True, sync_perm=False)
if remove_retcode != 0:
msg = m18n.n('app_not_properly_removed',
app=app_instance_name)
logger.warning(msg)
operation_logger_remove.error(msg)
else:
try:
_assert_system_is_sane_for_app(manifest, "post")
except Exception as e:
operation_logger_remove.error(e)
else:
try:
_assert_system_is_sane_for_app(manifest, "post")
except Exception as e:
operation_logger_remove.error(e)
else:
operation_logger_remove.success()
operation_logger_remove.success()
# Clean tmp folders
shutil.rmtree(app_setting_path)
shutil.rmtree(extracted_app_folder)
app_ssowatconf()
permission_sync_to_user()
if install_retcode == -1:
msg = m18n.n('operation_interrupted') + " " + error_msg
raise YunohostError(msg, raw_msg=True)
msg = error_msg
raise YunohostError(msg, raw_msg=True)
raise YunohostError(failure_message_with_debug_instructions, raw_msg=True)
# Clean hooks and add new ones
hook_remove(app_instance_name)
@ -996,12 +1098,14 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu
os.system('chown -R root: %s' % app_setting_path)
os.system('chown -R admin: %s/scripts' % app_setting_path)
# Add path in permission if it's defined in the app install script
# If an app doesn't have at least a domain and a path, assume it's not a webapp and remove the default "/" permission
app_settings = _get_app_settings(app_instance_name)
domain = app_settings.get('domain', None)
path = app_settings.get('path', None)
if domain and path:
permission_update(app_instance_name, permission="main", add_url=[domain+path], sync_perm=False)
if not (domain and path):
permission_url(app_instance_name + ".main", url=None, sync_perm=False)
_migrate_legacy_permissions(app_instance_name)
permission_sync_to_user()
@ -1010,6 +1114,34 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu
hook_callback('post_app_install', args=args_list, env=env_dict)
def _migrate_legacy_permissions(app):
from yunohost.permission import user_permission_list, user_permission_update
# Check if app is apparently using the legacy permission management, defined by the presence of something like
# ynh_app_setting_set on unprotected_uris (or yunohost app setting)
install_script_path = os.path.join(APPS_SETTING_PATH, app, 'scripts/install')
install_script_content = open(install_script_path, "r").read()
if not re.search(r"(yunohost app setting|ynh_app_setting_set) .*(unprotected|skipped)_uris", install_script_content):
return
app_settings = _get_app_settings(app)
app_perm_currently_allowed = user_permission_list()["permissions"][app + ".main"]["allowed"]
settings_say_it_should_be_public = (app_settings.get("unprotected_uris", None) == "/"
or app_settings.get("skipped_uris", None) == "/")
# If the current permission says app is protected, but there are legacy rules saying it should be public...
if app_perm_currently_allowed == ["all_users"] and settings_say_it_should_be_public:
# Make it public
user_permission_update(app + ".main", remove="all_users", add="visitors", sync_perm=False)
# If the current permission says app is public, but there are no setting saying it should be public...
if app_perm_currently_allowed == ["visitors"] and not settings_say_it_should_be_public:
# Make is private
user_permission_update(app + ".main", remove="visitors", add="all_users", sync_perm=False)
@is_unit_operation()
def app_remove(operation_logger, app):
"""
@ -1019,9 +1151,8 @@ def app_remove(operation_logger, app):
app -- App(s) to delete
"""
from yunohost.utils.ldap import _get_ldap_interface
from yunohost.hook import hook_exec, hook_remove, hook_callback
from yunohost.permission import permission_remove, permission_sync_to_user
from yunohost.permission import user_permission_list, permission_delete, permission_sync_to_user
if not _is_installed(app):
raise YunohostError('app_not_installed', app=app, all_apps=_get_all_installed_apps_id())
@ -1057,11 +1188,24 @@ def app_remove(operation_logger, app):
operation_logger.extra.update({'env': env_dict})
operation_logger.flush()
if hook_exec('/tmp/yunohost_remove/scripts/remove', args=args_list,
env=env_dict)[0] == 0:
logger.success(m18n.n('app_removed', app=app))
try:
ret = hook_exec('/tmp/yunohost_remove/scripts/remove',
args=args_list,
env=env_dict)[0]
# Here again, calling hook_exec could fail miserably, or get
# manually interrupted (by mistake or because script was stuck)
# In that case we still want to proceed with the rest of the
# removal (permissions, /etc/yunohost/apps/{app} ...)
except (KeyboardInterrupt, EOFError, Exception):
ret = -1
import traceback
logger.exception(m18n.n('unexpected_error', error=u"\n" + traceback.format_exc()))
if ret == 0:
logger.success(m18n.n('app_removed', app=app))
hook_callback('post_app_remove', args=args_list, env=env_dict)
else:
logger.warning(m18n.n('app_not_properly_removed', app=app))
if os.path.exists(app_setting_path):
shutil.rmtree(app_setting_path)
@ -1069,19 +1213,15 @@ def app_remove(operation_logger, app):
hook_remove(app)
# Remove all permission in LDAP
ldap = _get_ldap_interface()
result = ldap.search(base='ou=permission,dc=yunohost,dc=org',
filter='(&(objectclass=permissionYnh)(cn=*.%s))' % app, attrs=['cn'])
permission_list = [p['cn'][0] for p in result]
for l in permission_list:
permission_remove(app, l.split('.')[0], force=True, sync_perm=False)
for permission_name in user_permission_list()["permissions"].keys():
if permission_name.startswith(app+"."):
permission_delete(permission_name, force=True, sync_perm=False)
permission_sync_to_user()
_assert_system_is_sane_for_app(manifest, "post")
@is_unit_operation(['permission','app'])
def app_addaccess(operation_logger, apps, users=[]):
def app_addaccess(apps, users=[]):
"""
Grant access right to users (everyone by default)
@ -1092,15 +1232,17 @@ def app_addaccess(operation_logger, apps, users=[]):
"""
from yunohost.permission import user_permission_update
permission = user_permission_update(operation_logger, app=apps, permission="main", add_username=users)
logger.warning("/!\\ Packagers ! This app is using the legacy permission system. Please use the new helpers ynh_permission_{create,url,update,delete} and the 'visitors' group to manage permissions.")
result = {p : v['main']['allowed_users'] for p, v in permission['permissions'].items()}
output = {}
for app in apps:
permission = user_permission_update(app+".main", add=users, remove="all_users")
output[app] = permission["corresponding_users"]
return {'allowed_users': result}
return {'allowed_users': output}
@is_unit_operation(['permission','app'])
def app_removeaccess(operation_logger, apps, users=[]):
def app_removeaccess(apps, users=[]):
"""
Revoke access right to users (everyone by default)
@ -1111,15 +1253,17 @@ def app_removeaccess(operation_logger, apps, users=[]):
"""
from yunohost.permission import user_permission_update
permission = user_permission_update(operation_logger, app=apps, permission="main", del_username=users)
logger.warning("/!\\ Packagers ! This app is using the legacy permission system. Please use the new helpers ynh_permission_{create,url,update,delete} and the 'visitors' group to manage permissions.")
result = {p : v['main']['allowed_users'] for p, v in permission['permissions'].items()}
output = {}
for app in apps:
permission = user_permission_update(app+".main", remove=users)
output[app] = permission["corresponding_users"]
return {'allowed_users': result}
return {'allowed_users': output}
@is_unit_operation(['permission','app'])
def app_clearaccess(operation_logger, apps):
def app_clearaccess(apps):
"""
Reset access rights for the app
@ -1127,13 +1271,17 @@ def app_clearaccess(operation_logger, apps):
apps
"""
from yunohost.permission import user_permission_clear
from yunohost.permission import user_permission_reset
permission = user_permission_clear(operation_logger, app=apps, permission="main")
logger.warning("/!\\ Packagers ! This app is using the legacy permission system. Please use the new helpers ynh_permission_{create,url,update,delete} and the 'visitors' group to manage permissions.")
result = {p : v['main']['allowed_users'] for p, v in permission['permissions'].items()}
output = {}
for app in apps:
permission = user_permission_reset(app+".main")
output[app] = permission["corresponding_users"]
return {'allowed_users': output}
return {'allowed_users': result}
def app_debug(app):
"""
@ -1184,25 +1332,21 @@ def app_makedefault(operation_logger, app, domain=None):
raise YunohostError('app_make_default_location_already_used', app=app, domain=app_domain,
other_app=app_map(raw=True)[domain]["/"]["id"])
try:
with open('/etc/ssowat/conf.json.persistent') as json_conf:
ssowat_conf = json.loads(str(json_conf.read()))
except ValueError as e:
raise YunohostError('ssowat_persistent_conf_read_error', error=e)
except IOError:
# TODO / FIXME : current trick is to add this to conf.json.persisten
# This is really not robust and should be improved
# e.g. have a flag in /etc/yunohost/apps/$app/ to say that this is the
# default app or idk...
if not os.path.exists('/etc/ssowat/conf.json.persistent'):
ssowat_conf = {}
else:
ssowat_conf = read_json('/etc/ssowat/conf.json.persistent')
if 'redirected_urls' not in ssowat_conf:
ssowat_conf['redirected_urls'] = {}
ssowat_conf['redirected_urls'][domain + '/'] = app_domain + app_path
try:
with open('/etc/ssowat/conf.json.persistent', 'w+') as f:
json.dump(ssowat_conf, f, sort_keys=True, indent=4)
except IOError as e:
raise YunohostError('ssowat_persistent_conf_write_error', error=e)
write_to_json('/etc/ssowat/conf.json.persistent', ssowat_conf)
os.system('chmod 644 /etc/ssowat/conf.json.persistent')
logger.success(m18n.n('ssowat_conf_updated'))
@ -1227,15 +1371,24 @@ def app_setting(app, key, value=None, delete=False):
except Exception as e:
logger.debug("cannot get app setting '%s' for '%s' (%s)", key, app, e)
return None
if delete and key in app_settings:
del app_settings[key]
else:
if delete and key in app_settings:
del app_settings[key]
else:
# FIXME: Allow multiple values for some keys?
if key in ['redirected_urls', 'redirected_regex']:
value = yaml.load(value)
app_settings[key] = value
_set_app_settings(app, app_settings)
# FIXME: Allow multiple values for some keys?
if key in ['redirected_urls', 'redirected_regex']:
value = yaml.load(value)
if any(key.startswith(word+"_") for word in ["unprotected", "protected", "skipped"]):
logger.warning("/!\\ Packagers! This app is still using the skipped/protected/unprotected_uris/regex settings which are now obsolete and deprecated... Instead, you should use the new helpers 'ynh_permission_{create,urls,update,delete}' and the 'visitors' group to initialize the public/private access. Check out the documentation at the bottom of yunohost.org/groups_and_permissions to learn how to use the new permission mechanism.")
app_settings[key] = value
_set_app_settings(app, app_settings)
# Fucking legacy permission management.
# We need this because app temporarily set the app as unprotected to configure it with curl...
if key.startswith("unprotected_") or key.startswith("skipped_") and value == "/":
from permission import user_permission_update
user_permission_update(app + ".main", remove="all_users", add="visitors")
def app_checkport(port):
@ -1398,6 +1551,7 @@ def app_ssowatconf():
main_domain = _get_maindomain()
domains = domain_list()['domains']
all_permissions = user_permission_list(full=True)['permissions']
skipped_urls = []
skipped_regex = []
@ -1419,34 +1573,70 @@ def app_ssowatconf():
return s.split(',') if s else []
for app in apps_list:
with open(APPS_SETTING_PATH + app['id'] + '/settings.yml') as f:
app_settings = yaml.load(f)
if 'no_sso' in app_settings:
app_settings = read_yaml(APPS_SETTING_PATH + app['id'] + '/settings.yml')
if 'domain' not in app_settings:
continue
if 'path' not in app_settings:
continue
# This 'no_sso' settings sound redundant to not having $path defined ....
# At least from what I can see, all apps using it don't have a path defined ...
if 'no_sso' in app_settings:
continue
domain = app_settings['domain']
path = app_settings['path'].rstrip('/')
def _sanitized_absolute_url(perm_url):
# Nominal case : url is relative to the app's path
if perm_url.startswith("/"):
perm_domain = domain
perm_path = path + perm_url.rstrip("/")
# Otherwise, the urls starts with a domain name, like domain.tld/foo/bar
# We want perm_domain = domain.tld and perm_path = "/foo/bar"
else:
perm_domain, perm_path = perm_url.split("/", 1)
perm_path = "/" + perm_path.rstrip("/")
return perm_domain + perm_path
# Skipped
skipped_urls += [_sanitized_absolute_url(uri) for uri in _get_setting(app_settings, 'skipped_uris')]
skipped_regex += _get_setting(app_settings, 'skipped_regex')
# Redirected
redirected_urls.update(app_settings.get('redirected_urls', {}))
redirected_regex.update(app_settings.get('redirected_regex', {}))
# Legacy permission system using (un)protected_uris and _regex managed in app settings...
unprotected_urls += [_sanitized_absolute_url(uri) for uri in _get_setting(app_settings, 'unprotected_uris')]
protected_urls += [_sanitized_absolute_url(uri) for uri in _get_setting(app_settings, 'protected_uris')]
unprotected_regex += _get_setting(app_settings, 'unprotected_regex')
protected_regex += _get_setting(app_settings, 'protected_regex')
# New permission system
this_app_perms = {name: info for name, info in all_permissions.items() if name.startswith(app['id'] + ".")}
for perm_name, perm_info in this_app_perms.items():
# Ignore permissions for which there's no url defined
if not perm_info["url"]:
continue
for item in _get_setting(app_settings, 'skipped_uris'):
if item[-1:] == '/':
item = item[:-1]
skipped_urls.append(app_settings['domain'] + app_settings['path'].rstrip('/') + item)
for item in _get_setting(app_settings, 'skipped_regex'):
skipped_regex.append(item)
for item in _get_setting(app_settings, 'unprotected_uris'):
if item[-1:] == '/':
item = item[:-1]
unprotected_urls.append(app_settings['domain'] + app_settings['path'].rstrip('/') + item)
for item in _get_setting(app_settings, 'unprotected_regex'):
unprotected_regex.append(item)
for item in _get_setting(app_settings, 'protected_uris'):
if item[-1:] == '/':
item = item[:-1]
protected_urls.append(app_settings['domain'] + app_settings['path'].rstrip('/') + item)
for item in _get_setting(app_settings, 'protected_regex'):
protected_regex.append(item)
if 'redirected_urls' in app_settings:
redirected_urls.update(app_settings['redirected_urls'])
if 'redirected_regex' in app_settings:
redirected_regex.update(app_settings['redirected_regex'])
# FIXME : gotta handle regex-urls here... meh
url = _sanitized_absolute_url(perm_info["url"])
if "visitors" in perm_info["allowed"]:
unprotected_urls.append(url)
# Legacy stuff : we remove now unprotected-urls that might have been declared as protected earlier...
protected_urls = [u for u in protected_urls if u != url]
else:
# TODO : small optimization to implement : we don't need to explictly add all the app roots
protected_urls.append(url)
# Legacy stuff : we remove now unprotected-urls that might have been declared as protected earlier...
unprotected_urls = [u for u in unprotected_urls if u != url]
for domain in domains:
skipped_urls.extend([domain + '/yunohost/admin', domain + '/yunohost/api'])
@ -1455,12 +1645,14 @@ def app_ssowatconf():
skipped_regex.append("^[^/]*/%.well%-known/acme%-challenge/.*$")
skipped_regex.append("^[^/]*/%.well%-known/autoconfig/mail/config%-v1%.1%.xml.*$")
permission = {}
for a in user_permission_list()['permissions'].values():
for p in a.values():
if 'URL' in p:
for u in p['URL']:
permission[u] = p['allowed_users']
permissions_per_url = {}
for perm_name, perm_info in all_permissions.items():
# Ignore permissions for which there's no url defined
if not perm_info["url"]:
continue
permissions_per_url[perm_info["url"]] = perm_info['corresponding_users']
conf_dict = {
'portal_domain': main_domain,
@ -1482,7 +1674,7 @@ def app_ssowatconf():
'redirected_regex': redirected_regex,
'users': {username: app_map(user=username)
for username in user_list()['users'].keys()},
'permission': permission,
'permissions': permissions_per_url,
}
with open('/etc/ssowat/conf.json', 'w+') as f:
@ -2523,8 +2715,7 @@ def _parse_args_for_action(action, args={}):
def _parse_args_in_yunohost_format(args, action_args):
"""Parse arguments store in either manifest.json or actions.json
"""
from yunohost.domain import (domain_list, _get_maindomain,
_get_conflicting_apps, _normalize_domain_path)
from yunohost.domain import domain_list, _get_maindomain
from yunohost.user import user_info, user_list
args_dict = OrderedDict()
@ -2617,10 +2808,8 @@ def _parse_args_in_yunohost_format(args, action_args):
if arg_value not in domain_list()['domains']:
raise YunohostError('app_argument_invalid', name=arg_name, error=m18n.n('domain_unknown'))
elif arg_type == 'user':
try:
user_info(arg_value)
except YunohostError as e:
raise YunohostError('app_argument_invalid', name=arg_name, error=e)
if not arg_value in user_list()["users"].keys():
raise YunohostError('app_argument_invalid', name=arg_name, error=m18n.n('user_unknown', user=arg_value))
elif arg_type == 'app':
if not _is_installed(arg_value):
raise YunohostError('app_argument_invalid', name=arg_name, error=m18n.n('app_unknown'))
@ -2642,13 +2831,18 @@ def _parse_args_in_yunohost_format(args, action_args):
assert_password_is_strong_enough('user', arg_value)
args_dict[arg_name] = (arg_value, arg_type)
# END loop over action_args...
return args_dict
def _validate_and_normalize_webpath(manifest, args_dict, app_folder):
from yunohost.domain import _get_conflicting_apps, _normalize_domain_path
# If there's only one "domain" and "path", validate that domain/path
# is an available url and normalize the path.
domain_args = [ (name, value[0]) for name, value in args_dict.items() if value[1] == "domain" ]
path_args = [ (name, value[0]) for name, value in args_dict.items() if value[1] == "path" ]
domain_args = [(name, value[0]) for name, value in args_dict.items() if value[1] == "domain"]
path_args = [(name, value[0]) for name, value in args_dict.items() if value[1] == "path"]
if len(domain_args) == 1 and len(path_args) == 1:
@ -2674,7 +2868,25 @@ def _parse_args_in_yunohost_format(args, action_args):
# standard path format to deal with no matter what the user inputted)
args_dict[path_args[0][0]] = (path, "path")
return args_dict
# This is likely to be a full-domain app...
elif len(domain_args) == 1 and len(path_args) == 0:
# Confirm that this is a full-domain app This should cover most cases
# ... though anyway the proper solution is to implement some mechanism
# in the manifest for app to declare that they require a full domain
# (among other thing) so that we can dynamically check/display this
# requirement on the webadmin form and not miserably fail at submit time
# Full-domain apps typically declare something like path_url="/" or path=/
# and use ynh_webpath_register or yunohost_app_checkurl inside the install script
install_script_content = open(os.path.join(app_folder, 'scripts/install')).read()
if re.search(r"\npath(_url)?=[\"']?/[\"']?\n", install_script_content) \
and re.search(r"(ynh_webpath_register|yunohost app checkurl)", install_script_content):
domain = domain_args[0][1]
if _get_conflicting_apps(domain, "/"):
raise YunohostError('app_full_domain_unavailable', domain=domain)
def _make_environment_dict(args_dict, prefix="APP_ARG_"):

View file

@ -40,7 +40,7 @@ from moulinette import msignals, m18n
from yunohost.utils.error import YunohostError
from moulinette.utils import filesystem
from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import read_file, mkdir
from moulinette.utils.filesystem import read_file, mkdir, write_to_yaml, read_yaml
from yunohost.app import (
app_info, _is_installed, _parse_app_instance_name, _patch_php5
@ -602,10 +602,10 @@ class BackupManager():
env=env_dict,
chdir=self.work_dir)
ret_succeed = {hook: {path:result["state"] for path, result in infos.items()}
ret_succeed = {hook: [path for path, result in infos.items() if result["state"] == "succeed"]
for hook, infos in ret.items()
if any(result["state"] == "succeed" for result in infos.values())}
ret_failed = {hook: {path:result["state"] for path, result in infos.items.items()}
ret_failed = {hook: [path for path, result in infos.items.items() if result["state"] == "failed"]
for hook, infos in ret.items()
if any(result["state"] == "failed" for result in infos.values())}
@ -677,6 +677,8 @@ class BackupManager():
backup_app_failed -- Raised at the end if the app backup script
execution failed
"""
from yunohost.permission import user_permission_list
app_setting_path = os.path.join('/etc/yunohost/apps/', app)
# Prepare environment
@ -704,8 +706,9 @@ class BackupManager():
# backup permissions
logger.debug(m18n.n('backup_permission', app=app))
ldap_url = "ldap:///dc=yunohost,dc=org???(&(objectClass=permissionYnh)(cn=*.%s))" % app
os.system("slapcat -b dc=yunohost,dc=org -H '%s' -l '%s/permission.ldif'" % (ldap_url, settings_dir))
permissions = user_permission_list(full=True)["permissions"]
this_app_permissions = {name: infos for name, infos in permissions.items() if name.startswith(app + ".")}
write_to_yaml("%s/permissions.yml" % settings_dir, this_app_permissions)
except:
abs_tmp_app_dir = os.path.join(self.work_dir, 'apps/', app)
@ -919,7 +922,7 @@ class RestoreManager():
successfull_apps = self.targets.list("apps", include=["Success", "Warning"])
permission_sync_to_user(force=False)
permission_sync_to_user()
if os.path.ismount(self.work_dir):
ret = subprocess.call(["umount", self.work_dir])
@ -1131,6 +1134,8 @@ class RestoreManager():
self._restore_system()
self._restore_apps()
except Exception as e:
raise YunohostError("The following critical error happened during restoration: %s" % e)
finally:
self.clean()
@ -1183,18 +1188,12 @@ class RestoreManager():
if system_targets == []:
return
from yunohost.utils.ldap import _get_ldap_interface
ldap = _get_ldap_interface()
from yunohost.user import user_group_list
from yunohost.permission import permission_create, permission_delete, user_permission_update, user_permission_list, permission_sync_to_user
# Backup old permission for apps
# We need to do that because in case of an app is installed we can't remove the permission for this app
old_apps_permission = []
try:
old_apps_permission = ldap.search('ou=permission,dc=yunohost,dc=org',
'(&(objectClass=permissionYnh)(!(cn=main.mail))(!(cn=main.metronome))(!(cn=main.sftp)))',
['cn', 'objectClass', 'groupPermission', 'URL', 'gidNumber'])
except:
logger.info(m18n.n('apps_permission_not_found'))
old_apps_permission = user_permission_list(ignore_system_perms=True, full=True)["permissions"]
# Start register change on system
operation_logger = OperationLogger('backup_restore_system')
@ -1232,12 +1231,11 @@ class RestoreManager():
regen_conf()
# Check if we need to do the migration 0009 : setup group and permission
# Check that at least a group exists (all_users) to know if we need to
# do the migration 0011 : setup group and permission
#
# Legacy code
result = ldap.search('ou=groups,dc=yunohost,dc=org',
'(&(objectclass=groupOfNamesYnh)(cn=all_users))',
['cn'])
if not result:
if not "all_users" in user_group_list()["groups"].keys():
from yunohost.tools import _get_migration_by_name
setup_group_permission = _get_migration_by_name("setup_group_permission")
# Update LDAP schema restart slapd
@ -1245,24 +1243,17 @@ class RestoreManager():
regen_conf(names=['slapd'], force=True)
setup_group_permission.migrate_LDAP_db()
# Remove all permission for all app which sill in the LDAP
for per in ldap.search('ou=permission,dc=yunohost,dc=org',
'(&(objectClass=permissionYnh)(!(cn=main.mail))(!(cn=main.metronome))(!(cn=main.sftp)))',
['cn']):
if not ldap.remove('cn=%s,ou=permission' % per['cn'][0]):
raise YunohostError('permission_deletion_failed',
permission=per['cn'][0].split('.')[0],
app=per['cn'][0].split('.')[1])
# Remove all permission for all app which is still in the LDAP
for permission_name in user_permission_list(ignore_system_perms=True)["permissions"].keys():
permission_delete(permission_name, force=True, sync_perm=False)
# Restore permission for the app which is installed
for per in old_apps_permission:
try:
permission_name, app_name = per['cn'][0].split('.')
except:
logger.warning(m18n.n('permission_name_not_valid', permission=per['cn'][0]))
for permission_name, permission_infos in old_apps_permission.items():
app_name = permission_name.split(".")[0]
if _is_installed(app_name):
if not ldap.add('cn=%s,ou=permission' % per['cn'][0], per):
raise YunohostError('apps_permission_restoration_failed', permission=permission_name, app=app_name)
permission_create(permission_name, url=permission_infos["url"], allowed=permission_infos["allowed"], sync_perm=False)
permission_sync_to_user()
def _restore_apps(self):
@ -1271,7 +1262,6 @@ class RestoreManager():
apps_targets = self.targets.list("apps", exclude=["Skipped"])
for app in apps_targets:
print(app)
self._restore_app(app)
def _restore_app(self, app_instance_name):
@ -1301,11 +1291,8 @@ class RestoreManager():
name already exists
restore_app_failed -- Raised if the restore bash script failed
"""
from moulinette.utils.filesystem import read_ldif
from yunohost.user import user_group_list
from yunohost.permission import permission_remove
from yunohost.utils.ldap import _get_ldap_interface
ldap = _get_ldap_interface()
from yunohost.permission import permission_create, permission_delete, user_permission_list, user_permission_update, permission_sync_to_user
def copytree(src, dst, symlinks=False, ignore=None):
for item in os.listdir(src):
@ -1370,22 +1357,27 @@ class RestoreManager():
restore_script = os.path.join(tmp_folder_for_app_restore, 'restore')
# Restore permissions
if os.path.isfile(app_settings_in_archive + '/permission.ldif'):
filtred_entries = ['entryUUID', 'creatorsName', 'createTimestamp', 'entryCSN', 'structuralObjectClass',
'modifiersName', 'modifyTimestamp', 'inheritPermission', 'memberUid']
entries = read_ldif('%s/permission.ldif' % app_settings_in_archive, filtred_entries)
group_list = user_group_list(['cn'])['groups']
for dn, entry in entries:
# Remove the group which has been removed
for group in entry['groupPermission']:
group_name = group.split(',')[0].split('=')[1]
if group_name not in group_list:
entry['groupPermission'].remove(group)
if not ldap.add('cn=%s,ou=permission' % entry['cn'][0], entry):
raise YunohostError('apps_permission_restoration_failed',
permission=entry['cn'][0].split('.')[0],
app=entry['cn'][0].split('.')[1])
if os.path.isfile('%s/permissions.yml' % app_settings_new_path):
permissions = read_yaml('%s/permissions.yml' % app_settings_new_path)
existing_groups = user_group_list()['groups']
for permission_name, permission_infos in permissions.items():
if "allowed" not in permission_infos:
logger.warning("'allowed' key corresponding to allowed groups for permission %s not found when restoring app %s … You might have to reconfigure permissions yourself." % (permission_name, app_instance_name))
should_be_allowed = ["all_users"]
else:
should_be_allowed = [g for g in permission_infos["allowed"] if g in existing_groups]
permission_create(permission_name, url=permission_infos.get("url", None), allowed=should_be_allowed, sync_perm=False)
permission_sync_to_user()
os.remove('%s/permissions.yml' % app_settings_new_path)
else:
# Otherwise, we need to migrate the legacy permissions of this
# app (included in its settings.yml)
from yunohost.tools import _get_migration_by_name
setup_group_permission = _get_migration_by_name("setup_group_permission")
setup_group_permission.migrate_app_permission(app=app_instance_name)
@ -1424,7 +1416,6 @@ class RestoreManager():
operation_logger.start()
# Execute remove script
# TODO: call app_remove instead
if hook_exec(remove_script, args=[app_instance_name],
env=env_dict_remove)[0] != 0:
msg = m18n.n('app_not_properly_removed', app=app_instance_name)
@ -1436,12 +1427,10 @@ class RestoreManager():
# Cleaning app directory
shutil.rmtree(app_settings_new_path, ignore_errors=True)
# Remove all permission in LDAP
result = ldap.search(base='ou=permission,dc=yunohost,dc=org',
filter='(&(objectclass=permissionYnh)(cn=*.%s))' % app_instance_name, attrs=['cn'])
permission_list = [p['cn'][0] for p in result]
for l in permission_list:
permission_remove(app_instance_name, l.split('.')[0], force=True)
# Remove all permission in LDAP for this app
for permission_name in user_permission_list()["permissions"].keys():
if permission_name.startswith(app_instance_name+"."):
permission_delete(permission_name, force=True)
# TODO Cleaning app hooks
else:
@ -2384,6 +2373,15 @@ def backup_info(name, with_details=False, human_readable=False):
if "size_details" in info.keys():
for category in ["apps", "system"]:
for name, key_info in info[category].items():
if category == "system":
# Stupid legacy fix for weird format between 3.5 and 3.6
if isinstance(key_info, dict):
key_info = key_info.keys()
info[category][name] = key_info = {"paths": key_info}
else:
info[category][name] = key_info
if name in info["size_details"][category].keys():
key_info["size"] = info["size_details"][category][name]
if human_readable:

View file

@ -1,17 +1,16 @@
import yaml
import time
import os
from moulinette import m18n
from yunohost.utils.error import YunohostError
from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import read_yaml
from yunohost.tools import Migration
from yunohost.user import user_group_add, user_group_update
from yunohost.user import user_group_create, user_group_update
from yunohost.app import app_setting, app_list
from yunohost.regenconf import regen_conf
from yunohost.permission import permission_add, permission_sync_to_user
from yunohost.user import user_permission_add
from yunohost.regenconf import regen_conf, BACKUP_CONF_DIR
from yunohost.permission import permission_create, user_permission_update, permission_sync_to_user
logger = getActionLogger('yunohost.migration')
@ -19,6 +18,7 @@ logger = getActionLogger('yunohost.migration')
# Tools used also for restoration
###################################################
class MyMigration(Migration):
"""
Update the LDAP DB to be able to store the permission
@ -28,6 +28,28 @@ class MyMigration(Migration):
required = True
def remove_if_exists(self, target):
from yunohost.utils.ldap import _get_ldap_interface
ldap = _get_ldap_interface()
try:
objects = ldap.search(target + ",dc=yunohost,dc=org")
# ldap search will raise an exception if no corresponding object is found >.> ...
except Exception as e:
logger.debug("%s does not exist, no need to delete it" % target)
return
objects.reverse()
for o in objects:
for dn in o["dn"]:
dn = dn.replace(",dc=yunohost,dc=org", "")
logger.debug("Deleting old object %s ..." % dn)
try:
ldap.remove(dn)
except Exception as e:
raise YunohostError("migration_0011_failed_to_remove_stale_object", dn=dn, error=e)
def migrate_LDAP_db(self):
logger.info(m18n.n("migration_0011_update_LDAP_database"))
@ -35,21 +57,24 @@ class MyMigration(Migration):
from yunohost.utils.ldap import _get_ldap_interface
ldap = _get_ldap_interface()
try:
ldap.remove('cn=sftpusers,ou=groups')
except:
logger.warn(m18n.n("error_when_removing_sftpuser_group"))
with open('/usr/share/yunohost/yunohost-config/moulinette/ldap_scheme.yml') as f:
ldap_map = yaml.load(f)
ldap_map = read_yaml('/usr/share/yunohost/yunohost-config/moulinette/ldap_scheme.yml')
try:
self.remove_if_exists("ou=permission")
self.remove_if_exists('ou=groups')
attr_dict = ldap_map['parents']['ou=permission']
ldap.add('ou=permission', attr_dict)
attr_dict = ldap_map['parents']['ou=groups']
ldap.add('ou=groups', attr_dict)
attr_dict = ldap_map['children']['cn=all_users,ou=groups']
ldap.add('cn=all_users,ou=groups', attr_dict)
attr_dict = ldap_map['children']['cn=visitors,ou=groups']
ldap.add('cn=visitors,ou=groups', attr_dict)
for rdn, attr_dict in ldap_map['depends_children'].items():
ldap.add(rdn, attr_dict)
except Exception as e:
@ -65,10 +90,8 @@ class MyMigration(Migration):
username = user_info['uid'][0]
ldap.update('uid=%s,ou=users' % username,
{'objectClass': ['mailAccount', 'inetOrgPerson', 'posixAccount', 'userPermissionYnh']})
user_group_add(username, gid=user_info['uidNumber'][0], sync_perm=False)
user_group_update(groupname=username, add_user=username, force=True, sync_perm=False)
user_group_update(groupname='all_users', add_user=username, force=True, sync_perm=False)
user_group_create(username, gid=user_info['uidNumber'][0], primary_group=True, sync_perm=False)
user_group_update(groupname='all_users', add=username, force=True, sync_perm=False)
def migrate_app_permission(self, app=None):
logger.info(m18n.n("migration_0011_migrate_permission"))
@ -84,20 +107,32 @@ class MyMigration(Migration):
path = app_setting(app, 'path')
domain = app_setting(app, 'domain')
urls = [domain + path] if domain and path else None
permission_add(app, permission='main', urls=urls, default_allow=True, sync_perm=False)
url = "/" if domain and path else None
if permission:
allowed_group = permission.split(',')
user_permission_add([app], permission='main', group=allowed_group, sync_perm=False)
allowed_groups = permission.split(',')
else:
allowed_groups = ["all_users"]
permission_create(app+".main", url=url, allowed=allowed_groups, sync_perm=False)
app_setting(app, 'allowed_users', delete=True)
# Migrate classic public app still using the legacy unprotected_uris
if app_setting(app, "unprotected_uris") == "/" or app_setting(app, "skipped_uris") == "/":
user_permission_update(app+".main", remove="all_users", add="visitors", sync_perm=False)
permission_sync_to_user()
def run(self):
# FIXME : what do we really want to do here ...
# Imho we should just force-regen the conf in all case, and maybe
# just display a warning if we detect that the conf was manually modified
# Check if the migration can be processed
ldap_regen_conf_status = regen_conf(names=['slapd'], dry_run=True)
# By this we check if the have been customized
if ldap_regen_conf_status and ldap_regen_conf_status['slapd']['pending']:
raise YunohostError("migration_0011_LDAP_config_dirty")
logger.warning(m18n.n("migration_0011_slapd_config_will_be_overwritten", conf_backup_folder=BACKUP_CONF_DIR))
# Backup LDAP and the apps settings before to do the migration
logger.info(m18n.n("migration_0011_backup_before_migration"))

View file

@ -112,8 +112,10 @@ def domain_add(operation_logger, domain, dyndns=False):
'virtualdomain': domain,
}
if not ldap.add('virtualdomain=%s,ou=domains' % domain, attr_dict):
raise YunohostError('domain_creation_failed')
try:
ldap.add('virtualdomain=%s,ou=domains' % domain, attr_dict)
except Exception as e:
raise YunohostError('domain_creation_failed', domain=domain, error=e)
# Don't regen these conf if we're still in postinstall
if os.path.exists('/etc/yunohost/installed'):
@ -167,10 +169,12 @@ def domain_remove(operation_logger, domain, force=False):
operation_logger.start()
ldap = _get_ldap_interface()
if ldap.remove('virtualdomain=' + domain + ',ou=domains') or force:
os.system('rm -rf /etc/yunohost/certs/%s' % domain)
else:
raise YunohostError('domain_deletion_failed')
try:
ldap.remove('virtualdomain=' + domain + ',ou=domains')
except Exception as e:
raise YunohostError('domain_deletion_failed', domain=domain, error=e)
os.system('rm -rf /etc/yunohost/certs/%s' % domain)
regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix'])
app_ssowatconf()

View file

@ -212,7 +212,7 @@ def dyndns_update(operation_logger, dyn_host="dyndns.yunohost.org", domain=None,
from yunohost.tools import _get_migration_by_name
migration = _get_migration_by_name("migrate_to_tsig_sha256")
try:
migration.migrate(dyn_host, domain, key)
migration.run(dyn_host, domain, key)
except Exception as e:
logger.error(m18n.n('migrations_migration_has_failed',
exception=e,

View file

@ -196,7 +196,7 @@ def hook_list(action, list_by='name', show_info=False):
else:
_append_folder(result, HOOK_FOLDER)
except OSError:
logger.debug("system hook folder not found for action '%s' in %s",
logger.debug("No default hook for action '%s' in %s",
action, HOOK_FOLDER)
try:
@ -207,7 +207,7 @@ def hook_list(action, list_by='name', show_info=False):
else:
_append_folder(result, CUSTOM_HOOK_FOLDER)
except OSError:
logger.debug("custom hook folder not found for action '%s' in %s",
logger.debug("No custom hook for action '%s' in %s",
action, CUSTOM_HOOK_FOLDER)
return {'hooks': result}

View file

@ -44,7 +44,7 @@ CATEGORIES = ['operation', 'history', 'package', 'system', 'access', 'service',
'app']
METADATA_FILE_EXT = '.yml'
LOG_FILE_EXT = '.log'
RELATED_CATEGORIES = ['app', 'domain', 'service', 'user']
RELATED_CATEGORIES = ['app', 'domain', 'group', 'service', 'user']
logger = getActionLogger('yunohost.log')
@ -213,7 +213,7 @@ def log_display(path, number=None, share=False):
return infos
def is_unit_operation(entities=['app', 'domain', 'service', 'user'],
def is_unit_operation(entities=['app', 'domain', 'group', 'service', 'user'],
exclude=['password'], operation_key=None):
"""
Configure quickly a unit operation
@ -315,7 +315,8 @@ class RedactingFormatter(Formatter):
try:
# This matches stuff like db_pwd=the_secret or admin_password=other_secret
# (the secret part being at least 3 chars to avoid catching some lines like just "db_pwd=")
match = re.search(r'(pwd|pass|password|secret|key|token)=(\S{3,})$', record.strip())
# For 'key', we require to at least have one word char [a-zA-Z0-9_] before it to avoid catching "--key" used in many helpers
match = re.search(r'(pwd|pass|password|secret|\wkey|token)=(\S{3,})$', record.strip())
if match and match.group(2) not in self.data_to_redact:
self.data_to_redact.append(match.group(2))
except Exception as e:
@ -502,7 +503,10 @@ class OperationLogger(object):
The missing of the message below could help to see an electrical
shortage.
"""
self.error(m18n.n('log_operation_unit_unclosed_properly'))
if self.ended_at is not None or self.started_at is None:
return
else:
self.error(m18n.n('log_operation_unit_unclosed_properly'))
def _get_description_from_name(name):

View file

@ -24,6 +24,7 @@
Manage permissions
"""
import copy
import grp
import random
@ -35,309 +36,268 @@ from yunohost.log import is_unit_operation
logger = getActionLogger('yunohost.user')
SYSTEM_PERMS = ["mail", "xmpp", "stfp"]
def user_permission_list(app=None, permission=None, username=None, group=None):
#
#
# The followings are the methods exposed through the "yunohost user permission" interface
#
#
def user_permission_list(short=False, full=False, ignore_system_perms=False):
"""
List permission for specific application
Keyword argument:
app -- an application OR sftp, xmpp (metronome), mail
permission -- name of the permission ("main" by default)
username -- Username to get informations
group -- Groupname to get informations
List permissions and corresponding accesses
"""
from yunohost.utils.ldap import _get_ldap_interface
# Fetch relevant informations
from yunohost.utils.ldap import _get_ldap_interface, _ldap_path_extract
ldap = _get_ldap_interface()
permissions_infos = ldap.search('ou=permission,dc=yunohost,dc=org',
'(objectclass=permissionYnh)',
["cn", 'groupPermission', 'inheritPermission', 'URL'])
permission_attrs = [
'cn',
'groupPermission',
'inheritPermission',
'URL',
]
# Normally app is alway defined but it should be possible to set it
if app and not isinstance(app, list):
app = [app]
if permission and not isinstance(permission, list):
permission = [permission]
if not isinstance(username, list):
username = [username]
if not isinstance(group, list):
group = [group]
# Parse / organize information to be outputed
permissions = {}
for infos in permissions_infos:
result = ldap.search('ou=permission,dc=yunohost,dc=org',
'(objectclass=permissionYnh)', permission_attrs)
name = infos['cn'][0]
for res in result:
try:
permission_name, app_name = res['cn'][0].split('.')
except:
logger.warning(m18n.n('permission_name_not_valid', permission=res['cn'][0]))
group_name = []
if 'groupPermission' in res:
for g in res['groupPermission']:
group_name.append(g.split("=")[1].split(",")[0])
user_name = []
if 'inheritPermission' in res:
for u in res['inheritPermission']:
user_name.append(u.split("=")[1].split(",")[0])
# Don't show the result if the user defined a specific permission, user or group
if app and app_name not in app:
continue
if permission and permission_name not in permission:
continue
if username[0] and not set(username) & set(user_name):
continue
if group[0] and not set(group) & set(group_name):
if ignore_system_perms and name.split(".")[0] in SYSTEM_PERMS:
continue
if app_name not in permissions:
permissions[app_name] = {}
permissions[name] = {}
permissions[name]["allowed"] = [_ldap_path_extract(p, "cn") for p in infos.get('groupPermission', [])]
permissions[app_name][permission_name] = {'allowed_users': [], 'allowed_groups': []}
for g in group_name:
permissions[app_name][permission_name]['allowed_groups'].append(g)
for u in user_name:
permissions[app_name][permission_name]['allowed_users'].append(u)
if 'URL' in res:
permissions[app_name][permission_name]['URL'] = []
for u in res['URL']:
permissions[app_name][permission_name]['URL'].append(u)
if full:
permissions[name]["corresponding_users"] = [_ldap_path_extract(p, "uid") for p in infos.get('inheritPermission', [])]
permissions[name]["url"] = infos.get("URL", [None])[0]
if short:
permissions = permissions.keys()
return {'permissions': permissions}
def user_permission_update(operation_logger, app=[], permission=None, add_username=None, add_group=None, del_username=None, del_group=None, sync_perm=True):
@is_unit_operation()
def user_permission_update(operation_logger, permission, add=None, remove=None, sync_perm=True):
"""
Allow or Disallow a user or group to a permission for a specific application
Keyword argument:
app -- an application OR sftp, xmpp (metronome), mail
permission -- name of the permission ("main" by default)
add_username -- Username to allow
add_group -- Groupname to allow
del_username -- Username to disallow
del_group -- Groupname to disallow
permission -- Name of the permission (e.g. mail or or wordpress or wordpress.editors)
add -- List of groups or usernames to add to this permission
remove -- List of groups or usernames to remove from to this permission
"""
from yunohost.hook import hook_callback
from yunohost.user import user_group_list
from yunohost.utils.ldap import _get_ldap_interface
ldap = _get_ldap_interface()
if permission:
if not isinstance(permission, list):
permission = [permission]
else:
permission = ["main"]
# By default, manipulate main permission
if "." not in permission:
permission = permission + ".main"
if add_group:
if not isinstance(add_group, list):
add_group = [add_group]
else:
add_group = []
# Refuse to add "visitors" to mail, xmpp ... they require an account to make sense.
if add and "visitors" in add and permission.split(".")[0] in SYSTEM_PERMS:
raise YunohostError('permission_require_account', permission=permission)
if add_username:
if not isinstance(add_username, list):
add_username = [add_username]
else:
add_username = []
# Fetch currently allowed groups for this permission
if del_group:
if not isinstance(del_group, list):
del_group = [del_group]
else:
del_group = []
existing_permission = user_permission_list(full=True)["permissions"].get(permission, None)
if existing_permission is None:
raise YunohostError('permission_not_found', permission=permission)
if del_username:
if not isinstance(del_username, list):
del_username = [del_username]
else:
del_username = []
current_allowed_groups = existing_permission["allowed"]
all_existing_groups = user_group_list()['groups'].keys()
operation_logger.related_to.append(('app', permission.split(".")[0]))
# Validate that the group exist
for g in add_group:
if g not in user_group_list(['cn'])['groups']:
raise YunohostError('group_unknown', group=g)
for u in add_username:
if u not in user_list(['uid'])['users']:
raise YunohostError('user_unknown', user=u)
for g in del_group:
if g not in user_group_list(['cn'])['groups']:
raise YunohostError('group_unknown', group=g)
for u in del_username:
if u not in user_list(['uid'])['users']:
raise YunohostError('user_unknown', user=u)
# Compute new allowed group list (and make sure what we're doing make sense)
# Merge user and group (note that we consider all user as a group)
add_group.extend(add_username)
del_group.extend(del_username)
new_allowed_groups = copy.copy(current_allowed_groups)
if 'all_users' in add_group or 'all_users' in del_group:
raise YunohostError('edit_permission_with_group_all_users_not_allowed')
if add:
groups_to_add = [add] if not isinstance(add, list) else add
for group in groups_to_add:
if group not in all_existing_groups:
raise YunohostError('group_unknown', group=group)
if group in current_allowed_groups:
logger.warning(m18n.n('permission_already_allowed', permission=permission, group=group))
else:
operation_logger.related_to.append(('group', group))
# Populate permission informations
permission_attrs = [
'cn',
'groupPermission',
]
result = ldap.search('ou=permission,dc=yunohost,dc=org',
'(objectclass=permissionYnh)', permission_attrs)
result = {p['cn'][0]: p for p in result}
new_allowed_groups += groups_to_add
new_per_dict = {}
if remove:
groups_to_remove = [remove] if not isinstance(remove, list) else remove
for group in groups_to_remove:
if group not in all_existing_groups:
raise YunohostError('group_unknown', group=group)
if group not in current_allowed_groups:
logger.warning(m18n.n('permission_already_disallowed', permission=permission, group=group))
else:
operation_logger.related_to.append(('group', group))
for a in app:
for per in permission:
permission_name = per + '.' + a
if permission_name not in result:
raise YunohostError('permission_not_found', permission=per, app=a)
new_per_dict[permission_name] = set()
if 'groupPermission' in result[permission_name]:
new_per_dict[permission_name] = set(result[permission_name]['groupPermission'])
new_allowed_groups = [g for g in new_allowed_groups if g not in groups_to_remove]
for g in del_group:
if 'cn=all_users,ou=groups,dc=yunohost,dc=org' in new_per_dict[permission_name]:
raise YunohostError('need_define_permission_before')
group_name = 'cn=' + g + ',ou=groups,dc=yunohost,dc=org'
if group_name not in new_per_dict[permission_name]:
logger.warning(m18n.n('group_already_disallowed', permission=per, app=a, group=g))
else:
new_per_dict[permission_name].remove(group_name)
# If we end up with something like allowed groups is ["all_users", "volunteers"]
# we shall warn the users that they should probably choose between one or the other,
# because the current situation is probably not what they expect / is temporary ?
if 'cn=all_users,ou=groups,dc=yunohost,dc=org' in new_per_dict[permission_name]:
new_per_dict[permission_name].remove('cn=all_users,ou=groups,dc=yunohost,dc=org')
for g in add_group:
group_name = 'cn=' + g + ',ou=groups,dc=yunohost,dc=org'
if group_name in new_per_dict[permission_name]:
logger.warning(m18n.n('group_already_allowed', permission=per, app=a, group=g))
else:
new_per_dict[permission_name].add(group_name)
if len(new_allowed_groups) > 1:
if "all_users" in new_allowed_groups:
logger.warning(m18n.n("permission_currently_allowed_for_all_users"))
if "visitors" in new_allowed_groups:
logger.warning(m18n.n("permission_currently_allowed_for_visitors"))
# Don't update LDAP if we update exactly the same values
if set(new_allowed_groups) == set(current_allowed_groups):
logger.warning(m18n.n("permission_already_up_to_date"))
return existing_permission
# Commit the new allowed group list
operation_logger.start()
for per, val in new_per_dict.items():
# Don't update LDAP if we update exactly the same values
if val == set(result[per]['groupPermission'] if 'groupPermission' in result[per] else []):
continue
if ldap.update('cn=%s,ou=permission' % per, {'groupPermission': val}):
p = per.split('.')
logger.debug(m18n.n('permission_updated', permission=p[0], app=p[1]))
else:
raise YunohostError('permission_update_failed')
try:
ldap.update('cn=%s,ou=permission' % permission,
{'groupPermission': ['cn=' + g + ',ou=groups,dc=yunohost,dc=org' for g in new_allowed_groups]})
except Exception as e:
raise YunohostError('permission_update_failed', permission=permission, error=e)
logger.debug(m18n.n('permission_updated', permission=permission))
# Trigger permission sync if asked
if sync_perm:
permission_sync_to_user()
for a in app:
allowed_users = set()
disallowed_users = set()
group_list = user_group_list(['member'])['groups']
new_permission = user_permission_list(full=True)["permissions"][permission]
for g in add_group:
if 'members' in group_list[g]:
allowed_users.union(group_list[g]['members'])
for g in del_group:
if 'members' in group_list[g]:
disallowed_users.union(group_list[g]['members'])
# Trigger app callbacks
allowed_users = ','.join(allowed_users)
disallowed_users = ','.join(disallowed_users)
if add_group:
hook_callback('post_app_addaccess', args=[app, allowed_users])
if del_group:
hook_callback('post_app_removeaccess', args=[app, disallowed_users])
app = permission.split(".")[0]
return user_permission_list(app, permission)
old_allowed_users = set(existing_permission["corresponding_users"])
new_allowed_users = set(new_permission["corresponding_users"])
effectively_added_users = new_allowed_users - old_allowed_users
effectively_removed_users = old_allowed_users - new_allowed_users
if effectively_added_users:
hook_callback('post_app_addaccess', args=[app, ','.join(effectively_added_users)])
if effectively_removed_users:
hook_callback('post_app_removeaccess', args=[app, ','.join(effectively_removed_users)])
return new_permission
def user_permission_clear(operation_logger, app=[], permission=None, sync_perm=True):
@is_unit_operation()
def user_permission_reset(operation_logger, permission, sync_perm=True):
"""
Reset the permission for a specific application
Reset a given permission to just 'all_users'
Keyword argument:
app -- an application OR sftp, xmpp (metronome), mail
permission -- name of the permission ("main" by default)
username -- Username to get informations (all by default)
group -- Groupname to get informations (all by default)
permission -- Name of the permission (e.g. mail or nextcloud or wordpress.editors)
"""
from yunohost.hook import hook_callback
from yunohost.utils.ldap import _get_ldap_interface
ldap = _get_ldap_interface()
if permission:
if not isinstance(permission, list):
permission = [permission]
else:
permission = ["main"]
# By default, manipulate main permission
if "." not in permission:
permission = permission + ".main"
# Fetch existing permission
existing_permission = user_permission_list(full=True)["permissions"].get(permission, None)
if existing_permission is None:
raise YunohostError('permission_not_found', permission=permission)
if existing_permission["allowed"] == ["all_users"]:
logger.warning(m18n.n("permission_already_up_to_date"))
return
# Update permission with default (all_users)
operation_logger.related_to.append(('app', permission.split(".")[0]))
operation_logger.start()
default_permission = {'groupPermission': ['cn=all_users,ou=groups,dc=yunohost,dc=org']}
try:
ldap.update('cn=%s,ou=permission' % permission, default_permission)
except Exception as e:
raise YunohostError('permission_update_failed', permission=permission, error=e)
# Populate permission informations
permission_attrs = [
'cn',
'groupPermission',
]
result = ldap.search('ou=permission,dc=yunohost,dc=org',
'(objectclass=permissionYnh)', permission_attrs)
result = {p['cn'][0]: p for p in result}
logger.debug(m18n.n('permission_updated', permission=permission))
for a in app:
for per in permission:
permission_name = per + '.' + a
if permission_name not in result:
raise YunohostError('permission_not_found', permission=per, app=a)
if 'groupPermission' in result[permission_name] and 'cn=all_users,ou=groups,dc=yunohost,dc=org' in result[permission_name]['groupPermission']:
logger.warning(m18n.n('permission_already_clear', permission=per, app=a))
continue
if ldap.update('cn=%s,ou=permission' % permission_name, default_permission):
logger.debug(m18n.n('permission_updated', permission=per, app=a))
else:
raise YunohostError('permission_update_failed')
if sync_perm:
permission_sync_to_user()
permission_sync_to_user()
new_permission = user_permission_list(full=True)["permissions"][permission]
for a in app:
permission_name = 'main.' + a
result = ldap.search('ou=permission,dc=yunohost,dc=org',
filter='cn=' + permission_name, attrs=['inheritPermission'])
if result:
allowed_users = result[0]['inheritPermission']
new_user_list = ','.join(allowed_users)
hook_callback('post_app_removeaccess', args=[app, new_user_list])
# Trigger app callbacks
return user_permission_list(app, permission)
app = permission.split(".")[0]
old_allowed_users = set(existing_permission["corresponding_users"])
new_allowed_users = set(new_permission["corresponding_users"])
effectively_added_users = new_allowed_users - old_allowed_users
effectively_removed_users = old_allowed_users - new_allowed_users
if effectively_added_users:
hook_callback('post_app_addaccess', args=[app, ','.join(effectively_added_users)])
if effectively_removed_users:
hook_callback('post_app_removeaccess', args=[app, ','.join(effectively_removed_users)])
return new_permission
#
#
# The followings methods are *not* directly exposed.
# They are used to create/delete the permissions (e.g. during app install/remove)
# and by some app helpers to possibly add additional permissions
#
#
@is_unit_operation(['permission', 'app'])
def permission_add(operation_logger, app, permission, urls=None, default_allow=True, sync_perm=True):
@is_unit_operation()
def permission_create(operation_logger, permission, url=None, allowed=None, sync_perm=True):
"""
Create a new permission for a specific application
Keyword argument:
app -- an application OR sftp, xmpp (metronome), mail
permission -- name of the permission ("main" by default)
urls -- list of urls to specify for the permission
permission -- Name of the permission (e.g. mail or nextcloud or wordpress.editors)
url -- (optional) URL for which access will be allowed/forbidden
allowed -- (optional) A list of group/user to allow for the permission
If provided, 'url' is assumed to be relative to the app domain/path if they
start with '/'. For example:
/ -> domain.tld/app
/admin -> domain.tld/app/admin
domain.tld/app/api -> domain.tld/app/api
'url' can be later treated as a regex if it starts with "re:".
For example:
re:/api/[A-Z]*$ -> domain.tld/app/api/[A-Z]*$
re:domain.tld/app/api/[A-Z]*$ -> domain.tld/app/api/[A-Z]*$
"""
from yunohost.domain import _normalize_domain_path
from yunohost.user import user_group_list
from yunohost.utils.ldap import _get_ldap_interface
ldap = _get_ldap_interface()
# By default, manipulate main permission
if "." not in permission:
permission = permission + ".main"
# Validate uniqueness of permission in LDAP
permission_name = str(permission + '.' + app) # str(...) Fix encoding issue
conflict = ldap.get_conflict({
'cn': permission_name
}, base_dn='ou=permission,dc=yunohost,dc=org')
if conflict:
raise YunohostError('permission_already_exist', permission=permission, app=app)
if ldap.get_conflict({'cn': permission},
base_dn='ou=permission,dc=yunohost,dc=org'):
raise YunohostError('permission_already_exist', permission=permission)
# Get random GID
all_gid = {x.gr_gid for x in grp.getgrall()}
@ -349,177 +309,162 @@ def permission_add(operation_logger, app, permission, urls=None, default_allow=T
attr_dict = {
'objectClass': ['top', 'permissionYnh', 'posixGroup'],
'cn': permission_name,
'cn': str(permission),
'gidNumber': gid,
}
if default_allow:
attr_dict['groupPermission'] = 'cn=all_users,ou=groups,dc=yunohost,dc=org'
if urls:
attr_dict['URL'] = []
for url in urls:
domain = url[:url.index('/')]
path = url[url.index('/'):]
domain, path = _normalize_domain_path(domain, path)
attr_dict['URL'].append(domain + path)
# If who should be allowed is explicitly provided, use this info
if allowed:
if not isinstance(allowed, list):
allowed = [allowed]
# (though first we validate that the targets actually exist)
all_existing_groups = user_group_list()['groups'].keys()
for g in allowed:
if g not in all_existing_groups:
raise YunohostError('group_unknown', group=g)
attr_dict['groupPermission'] = ['cn=%s,ou=groups,dc=yunohost,dc=org' % g for g in allowed]
# For main permission, we add all users by default
elif permission.endswith(".main"):
attr_dict['groupPermission'] = ['cn=all_users,ou=groups,dc=yunohost,dc=org']
if url:
attr_dict['URL'] = url
operation_logger.related_to.append(('app', permission.split(".")[0]))
operation_logger.start()
if ldap.add('cn=%s,ou=permission' % permission_name, attr_dict):
if sync_perm:
permission_sync_to_user()
logger.debug(m18n.n('permission_created', permission=permission, app=app))
return user_permission_list(app, permission)
raise YunohostError('permission_creation_failed')
try:
ldap.add('cn=%s,ou=permission' % permission, attr_dict)
except Exception as e:
raise YunohostError('permission_creation_failed', permission=permission, error=e)
@is_unit_operation(['permission', 'app'])
def permission_update(operation_logger, app, permission, add_url=None, remove_url=None, sync_perm=True):
"""
Update a permission for a specific application
Keyword argument:
app -- an application OR sftp, xmpp (metronome), mail
permission -- name of the permission ("main" by default)
add_url -- Add a new url for a permission
remove_url -- Remove a url for a permission
"""
from yunohost.domain import _normalize_domain_path
from yunohost.utils.ldap import _get_ldap_interface
ldap = _get_ldap_interface()
permission_name = str(permission + '.' + app) # str(...) Fix encoding issue
# Populate permission informations
result = ldap.search(base='ou=permission,dc=yunohost,dc=org',
filter='cn=' + permission_name, attrs=['URL'])
if not result:
raise YunohostError('permission_not_found', permission=permission, app=app)
permission_obj = result[0]
if 'URL' not in permission_obj:
permission_obj['URL'] = []
url = set(permission_obj['URL'])
if add_url:
for u in add_url:
domain = u[:u.index('/')]
path = u[u.index('/'):]
domain, path = _normalize_domain_path(domain, path)
url.add(domain + path)
if remove_url:
for u in remove_url:
domain = u[:u.index('/')]
path = u[u.index('/'):]
domain, path = _normalize_domain_path(domain, path)
url.discard(domain + path)
if url == set(permission_obj['URL']):
logger.warning(m18n.n('permission_update_nothing_to_do'))
return user_permission_list(app, permission)
operation_logger.start()
if ldap.update('cn=%s,ou=permission' % permission_name, {'cn': permission_name, 'URL': url}):
if sync_perm:
permission_sync_to_user()
logger.debug(m18n.n('permission_updated', permission=permission, app=app))
return user_permission_list(app, permission)
raise YunohostError('premission_update_failed')
@is_unit_operation(['permission', 'app'])
def permission_remove(operation_logger, app, permission, force=False, sync_perm=True):
"""
Remove a permission for a specific application
Keyword argument:
app -- an application OR sftp, xmpp (metronome), mail
permission -- name of the permission ("main" by default)
"""
if permission == "main" and not force:
raise YunohostError('remove_main_permission_not_allowed')
from yunohost.utils.ldap import _get_ldap_interface
ldap = _get_ldap_interface()
operation_logger.start()
if not ldap.remove('cn=%s,ou=permission' % str(permission + '.' + app)):
raise YunohostError('permission_deletion_failed', permission=permission, app=app)
if sync_perm:
permission_sync_to_user()
logger.debug(m18n.n('permission_deleted', permission=permission, app=app))
logger.debug(m18n.n('permission_created', permission=permission))
return user_permission_list(full=True)["permissions"][permission]
def permission_sync_to_user(force=False):
@is_unit_operation()
def permission_url(operation_logger, permission, url=None, sync_perm=True):
"""
Update urls related to a permission for a specific application
Keyword argument:
permission -- Name of the permission (e.g. mail or nextcloud or wordpress.editors)
url -- (optional) URL for which access will be allowed/forbidden
"""
from yunohost.utils.ldap import _get_ldap_interface
ldap = _get_ldap_interface()
# Fetch existing permission
existing_permission = user_permission_list(full=True)["permissions"].get(permission, None)
if not existing_permission:
raise YunohostError('permission_not_found', permission=permission)
# Compute new url list
old_url = existing_permission["url"]
if old_url == url:
logger.warning(m18n.n('permission_update_nothing_to_do'))
return existing_permission
# Actually commit the change
operation_logger.related_to.append(('app', permission.split(".")[0]))
operation_logger.start()
try:
ldap.update('cn=%s,ou=permission' % permission, {'URL': [url]})
except Exception as e:
raise YunohostError('permission_update_failed', permission=permission, error=e)
if sync_perm:
permission_sync_to_user()
logger.debug(m18n.n('permission_updated', permission=permission))
return user_permission_list(full=True)["permissions"][permission]
@is_unit_operation()
def permission_delete(operation_logger, permission, force=False, sync_perm=True):
"""
Delete a permission
Keyword argument:
permission -- Name of the permission (e.g. mail or nextcloud or wordpress.editors)
"""
# By default, manipulate main permission
if "." not in permission:
permission = permission + ".main"
if permission.endswith(".main") and not force:
raise YunohostError('permission_cannot_remove_main')
from yunohost.utils.ldap import _get_ldap_interface
ldap = _get_ldap_interface()
# Make sure this permission exists
existing_permission = user_permission_list(full=True)["permissions"].get(permission, None)
if not existing_permission:
raise YunohostError('permission_not_found', permission=permission)
# Actually delete the permission
operation_logger.related_to.append(('app', permission.split(".")[0]))
operation_logger.start()
try:
ldap.remove('cn=%s,ou=permission' % permission)
except Exception as e:
raise YunohostError('permission_deletion_failed', permission=permission, error=e)
if sync_perm:
permission_sync_to_user()
logger.debug(m18n.n('permission_deleted', permission=permission))
def permission_sync_to_user():
"""
Sychronise the inheritPermission attribut in the permission object from the
user<->group link and the group<->permission link
Keyword argument:
force -- Force to recreate all attributes. Used generally with the
backup which uses "slapadd" which doesnt' use the memberOf overlay.
Note that by removing all value and adding a new time, we force the
overlay to update all attributes
"""
# Note that a LDAP operation with the same value that is in LDAP crash SLAP.
# So we need to check before each ldap operation that we really change something in LDAP
import os
from yunohost.app import app_ssowatconf
from yunohost.user import user_group_list
from yunohost.utils.ldap import _get_ldap_interface
ldap = _get_ldap_interface()
permission_attrs = [
'cn',
'member',
]
group_info = ldap.search('ou=groups,dc=yunohost,dc=org',
'(objectclass=groupOfNamesYnh)', permission_attrs)
group_info = {g['cn'][0]: g for g in group_info}
groups = user_group_list(full=True)["groups"]
permissions = user_permission_list(full=True)["permissions"]
for per in ldap.search('ou=permission,dc=yunohost,dc=org',
'(objectclass=permissionYnh)',
['cn', 'inheritPermission', 'groupPermission', 'memberUid']):
for permission_name, permission_infos in permissions.items():
if 'groupPermission' not in per:
per['groupPermission'] = []
user_permission = set()
for group in per['groupPermission']:
group = group.split("=")[1].split(",")[0]
if 'member' not in group_info[group]:
continue
for user in group_info[group]['member']:
user_permission.add(user)
# These are the users currently allowed because there's an 'inheritPermission' object corresponding to it
currently_allowed_users = set(permission_infos["corresponding_users"])
if 'inheritPermission' not in per:
per['inheritPermission'] = []
if 'memberUid' not in per:
per['memberUid'] = []
# These are the users that should be allowed because they are member of a group that is allowed for this permission ...
should_be_allowed_users = set([user for group in permission_infos["allowed"] for user in groups[group]["members"]])
uid_val = [v.split("=")[1].split(",")[0] for v in user_permission]
if user_permission == set(per['inheritPermission']) and set(uid_val) == set(per['memberUid']) and not force:
# Note that a LDAP operation with the same value that is in LDAP crash SLAP.
# So we need to check before each ldap operation that we really change something in LDAP
if currently_allowed_users == should_be_allowed_users:
# We're all good, this permission is already correctly synchronized !
continue
inheritPermission = {'inheritPermission': user_permission, 'memberUid': uid_val}
if force:
if per['groupPermission']:
if not ldap.update('cn=%s,ou=permission' % per['cn'][0], {'groupPermission': []}):
raise YunohostError('permission_update_failed_clear')
if not ldap.update('cn=%s,ou=permission' % per['cn'][0], {'groupPermission': per['groupPermission']}):
raise YunohostError('permission_update_failed_populate')
if per['inheritPermission']:
if not ldap.update('cn=%s,ou=permission' % per['cn'][0], {'inheritPermission': []}):
raise YunohostError('permission_update_failed_clear')
if user_permission:
if not ldap.update('cn=%s,ou=permission' % per['cn'][0], inheritPermission):
raise YunohostError('permission_update_failed')
else:
if not ldap.update('cn=%s,ou=permission' % per['cn'][0], inheritPermission):
raise YunohostError('permission_update_failed')
logger.debug(m18n.n('permission_generated'))
new_inherited_perms = {'inheritPermission': ["uid=%s,ou=users,dc=yunohost,dc=org" % u for u in should_be_allowed_users],
'memberUid': should_be_allowed_users}
# Commit the change with the new inherited stuff
try:
ldap.update('cn=%s,ou=permission' % permission_name, new_inherited_perms)
except Exception as e:
raise YunohostError('permission_update_failed', permission=permission_name, error=e)
logger.debug("The permission database has been resynchronized")
app_ssowatconf()

View file

@ -70,7 +70,7 @@ def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run
or not os.path.exists(REGEN_CONF_FILE)):
from yunohost.tools import _get_migration_by_name
migration = _get_migration_by_name("decouple_regenconf_from_services")
migration.migrate()
migration.run()
result = {}

View file

@ -1,9 +1,32 @@
import pytest
import sys
import moulinette
from moulinette import m18n
from yunohost.utils.error import YunohostError
from contextlib import contextmanager
sys.path.append("..")
@contextmanager
def message(mocker, key, **kwargs):
mocker.spy(m18n, "n")
yield
m18n.n.assert_any_call(key, **kwargs)
@contextmanager
def raiseYunohostError(mocker, key, **kwargs):
with pytest.raises(YunohostError) as e_info:
yield
assert e_info._excinfo[1].key == key
if kwargs:
assert e_info._excinfo[1].kwargs == kwargs
def pytest_addoption(parser):
parser.addoption("--yunodebug", action="store_true", default=False)

View file

@ -4,6 +4,8 @@ import pytest
import shutil
import requests
from conftest import message, raiseYunohostError
from moulinette import m18n
from moulinette.utils.filesystem import mkdir
@ -36,16 +38,22 @@ def clean():
if _is_installed("legacy_app"):
app_remove("legacy_app")
if _is_installed("full_domain_app"):
app_remove("full_domain_app")
to_remove = []
to_remove += glob.glob("/etc/nginx/conf.d/*.d/*legacy*")
to_remove += glob.glob("/etc/nginx/conf.d/*.d/*full_domain*")
to_remove += glob.glob("/etc/nginx/conf.d/*.d/*break_yo_system*")
for filepath in to_remove:
os.remove(filepath)
to_remove = []
to_remove += glob.glob("/etc/yunohost/apps/*legacy_app*")
to_remove += glob.glob("/etc/yunohost/apps/*full_domain_app*")
to_remove += glob.glob("/etc/yunohost/apps/*break_yo_system*")
to_remove += glob.glob("/var/www/*legacy*")
to_remove += glob.glob("/var/www/*full_domain*")
for folderpath in to_remove:
shutil.rmtree(folderpath, ignore_errors=True)
@ -107,16 +115,23 @@ def app_is_not_installed(domain, app):
def app_is_exposed_on_http(domain, path, message_in_page):
try:
r = requests.get("http://127.0.0.1" + path + "/", headers={"Host": domain}, timeout=10)
r = requests.get("http://127.0.0.1" + path + "/", headers={"Host": domain}, timeout=10, verify=False)
return r.status_code == 200 and message_in_page in r.text
except Exception:
except Exception as e:
return False
def install_legacy_app(domain, path):
def install_legacy_app(domain, path, public=True):
app_install("./tests/apps/legacy_app_ynh",
args="domain=%s&path=%s" % (domain, path),
args="domain=%s&path=%s&is_public=%s" % (domain, path, 1 if public else 0),
force=True)
def install_full_domain_app(domain):
app_install("./tests/apps/full_domain_app_ynh",
args="domain=%s" % domain,
force=True)
@ -167,13 +182,7 @@ def test_legacy_app_install_secondary_domain_on_root(secondary_domain):
def test_legacy_app_install_private(secondary_domain):
install_legacy_app(secondary_domain, "/legacy")
settings = open("/etc/yunohost/apps/legacy_app/settings.yml", "r").read()
new_settings = settings.replace("\nunprotected_uris: /", "")
assert new_settings != settings
open("/etc/yunohost/apps/legacy_app/settings.yml", "w").write(new_settings)
app_ssowatconf()
install_legacy_app(secondary_domain, "/legacy", public=False)
assert app_is_installed(secondary_domain, "legacy_app")
assert not app_is_exposed_on_http(secondary_domain, "/legacy", "This is a dummy app")
@ -183,11 +192,11 @@ def test_legacy_app_install_private(secondary_domain):
assert app_is_not_installed(secondary_domain, "legacy_app")
def test_legacy_app_install_unknown_domain():
def test_legacy_app_install_unknown_domain(mocker):
with pytest.raises(YunohostError):
install_legacy_app("whatever.nope", "/legacy")
# TODO check error message
with message(mocker, "app_argument_invalid"):
install_legacy_app("whatever.nope", "/legacy")
assert app_is_not_installed("whatever.nope", "legacy_app")
@ -214,55 +223,51 @@ def test_legacy_app_install_multiple_instances(secondary_domain):
assert app_is_not_installed(secondary_domain, "legacy_app__2")
def test_legacy_app_install_path_unavailable(secondary_domain):
def test_legacy_app_install_path_unavailable(mocker, secondary_domain):
# These will be removed in teardown
install_legacy_app(secondary_domain, "/legacy")
with pytest.raises(YunohostError):
install_legacy_app(secondary_domain, "/")
# TODO check error message
with message(mocker, "app_location_unavailable"):
install_legacy_app(secondary_domain, "/")
assert app_is_installed(secondary_domain, "legacy_app")
assert app_is_not_installed(secondary_domain, "legacy_app__2")
def test_legacy_app_install_bad_args():
with pytest.raises(YunohostError):
install_legacy_app("this.domain.does.not.exists", "/legacy")
def test_legacy_app_install_with_nginx_down(secondary_domain):
def test_legacy_app_install_with_nginx_down(mocker, secondary_domain):
os.system("systemctl stop nginx")
with pytest.raises(YunohostError):
with raiseYunohostError(mocker, "app_action_cannot_be_ran_because_required_services_down"):
install_legacy_app(secondary_domain, "/legacy")
def test_legacy_app_failed_install(secondary_domain):
def test_legacy_app_failed_install(mocker, secondary_domain):
# This will conflict with the folder that the app
# attempts to create, making the install fail
mkdir("/var/www/legacy_app/", 0o750)
with pytest.raises(YunohostError):
install_legacy_app(secondary_domain, "/legacy")
# TODO check error message
with message(mocker, 'app_install_script_failed'):
install_legacy_app(secondary_domain, "/legacy")
assert app_is_not_installed(secondary_domain, "legacy_app")
def test_legacy_app_failed_remove(secondary_domain):
def test_legacy_app_failed_remove(mocker, secondary_domain):
install_legacy_app(secondary_domain, "/legacy")
# The remove script runs with set -eu and attempt to remove this
# file without -f, so will fail if it's not there ;)
os.remove("/etc/nginx/conf.d/%s.d/%s.conf" % (secondary_domain, "legacy_app"))
with pytest.raises(YunohostError):
app_remove("legacy")
# TODO / FIXME : can't easily validate that 'app_not_properly_removed'
# is triggered for weird reasons ...
app_remove("legacy_app")
#
# Well here, we hit the classical issue where if an app removal script
@ -272,50 +277,68 @@ def test_legacy_app_failed_remove(secondary_domain):
assert app_is_not_installed(secondary_domain, "legacy")
def test_systemfuckedup_during_app_install(secondary_domain):
def test_full_domain_app(secondary_domain):
install_full_domain_app(secondary_domain)
assert app_is_exposed_on_http(secondary_domain, "/", "This is a dummy app")
def test_full_domain_app_with_conflicts(mocker, secondary_domain):
install_legacy_app(secondary_domain, "/legacy")
with raiseYunohostError(mocker, "app_full_domain_unavailable"):
install_full_domain_app(secondary_domain)
def test_systemfuckedup_during_app_install(mocker, secondary_domain):
with pytest.raises(YunohostError):
install_break_yo_system(secondary_domain, breakwhat="install")
os.system("nginx -t")
os.system("systemctl status nginx")
with message(mocker, "app_install_failed"):
with message(mocker, 'app_action_broke_system'):
install_break_yo_system(secondary_domain, breakwhat="install")
assert app_is_not_installed(secondary_domain, "break_yo_system")
def test_systemfuckedup_during_app_remove(secondary_domain):
def test_systemfuckedup_during_app_remove(mocker, secondary_domain):
install_break_yo_system(secondary_domain, breakwhat="remove")
with pytest.raises(YunohostError):
app_remove("break_yo_system")
os.system("nginx -t")
os.system("systemctl status nginx")
with message(mocker, 'app_action_broke_system'):
with message(mocker, 'app_removed'):
app_remove("break_yo_system")
assert app_is_not_installed(secondary_domain, "break_yo_system")
def test_systemfuckedup_during_app_install_and_remove(secondary_domain):
def test_systemfuckedup_during_app_install_and_remove(mocker, secondary_domain):
with pytest.raises(YunohostError):
install_break_yo_system(secondary_domain, breakwhat="everything")
with message(mocker, "app_install_failed"):
with message(mocker, 'app_action_broke_system'):
install_break_yo_system(secondary_domain, breakwhat="everything")
assert app_is_not_installed(secondary_domain, "break_yo_system")
def test_systemfuckedup_during_app_upgrade(secondary_domain):
def test_systemfuckedup_during_app_upgrade(mocker, secondary_domain):
install_break_yo_system(secondary_domain, breakwhat="upgrade")
with pytest.raises(YunohostError):
app_upgrade("break_yo_system", file="./tests/apps/break_yo_system_ynh")
with message(mocker, 'app_action_broke_system'):
app_upgrade("break_yo_system", file="./tests/apps/break_yo_system_ynh")
def test_failed_multiple_app_upgrade(secondary_domain):
def test_failed_multiple_app_upgrade(mocker, secondary_domain):
install_legacy_app(secondary_domain, "/legacy")
install_break_yo_system(secondary_domain, breakwhat="upgrade")
with pytest.raises(YunohostError):
with raiseYunohostError(mocker, 'app_not_upgraded'):
app_upgrade(["break_yo_system", "legacy_app"],
file={"break_yo_system": "./tests/apps/break_yo_system_ynh",
"legacy": "./tests/apps/legacy_app_ynh"})

View file

@ -2,15 +2,14 @@ import pytest
import os
import shutil
import subprocess
from mock import ANY
from moulinette import m18n
from conftest import message, raiseYunohostError
from yunohost.app import app_install, app_remove, app_ssowatconf
from yunohost.app import _is_installed
from yunohost.backup import backup_create, backup_restore, backup_list, backup_info, backup_delete, _recursive_umount
from yunohost.domain import _get_maindomain
from yunohost.utils.error import YunohostError
from yunohost.user import user_permission_list
from yunohost.user import user_permission_list, user_create, user_list, user_delete
from yunohost.tests.test_permission import check_LDAP_db_integrity, check_permission_for_apps
# Get main domain
@ -38,10 +37,10 @@ def setup_function(function):
add_archive_wordpress_from_2p4()
assert len(backup_list()["archives"]) == 1
if "with_backup_legacy_app_installed" in markers:
assert not app_is_installed("backup_legacy_app")
install_app("backup_legacy_app_ynh", "/yolo")
assert app_is_installed("backup_legacy_app")
if "with_legacy_app_installed" in markers:
assert not app_is_installed("legacy_app")
install_app("legacy_app_ynh", "/yolo")
assert app_is_installed("legacy_app")
if "with_backup_recommended_app_installed" in markers:
assert not app_is_installed("backup_recommended_app")
@ -59,6 +58,13 @@ def setup_function(function):
add_archive_system_from_2p4()
assert len(backup_list()["archives"]) == 1
if "with_permission_app_installed" in markers:
assert not app_is_installed("permissions_app")
user_create("alice", "Alice", "White", "alice@" + maindomain, "test123Ynh")
install_app("permissions_app_ynh", "/urlpermissionapp"
"&admin=alice")
assert app_is_installed("permissions_app")
def teardown_function(function):
@ -73,6 +79,9 @@ def teardown_function(function):
if "clean_opt_dir" in markers:
shutil.rmtree("/opt/test_backup_output_directory")
if "alice" in user_list()["users"]:
user_delete("alice")
@pytest.fixture(autouse=True)
def check_LDAP_db_integrity_call():
@ -92,6 +101,9 @@ def check_permission_for_apps_call():
def app_is_installed(app):
if app == "permissions_app":
return _is_installed(app)
# These are files we know should be installed by the app
app_files = []
app_files.append("/etc/nginx/conf.d/%s.d/%s.conf" % (maindomain, app))
@ -105,7 +117,7 @@ def backup_test_dependencies_are_met():
# Dummy test apps (or backup archives)
assert os.path.exists("./tests/apps/backup_wordpress_from_2p4")
assert os.path.exists("./tests/apps/backup_legacy_app_ynh")
assert os.path.exists("./tests/apps/legacy_app_ynh")
assert os.path.exists("./tests/apps/backup_recommended_app_ynh")
return True
@ -155,14 +167,9 @@ def delete_all_backups():
def uninstall_test_apps_if_needed():
if _is_installed("backup_legacy_app"):
app_remove("backup_legacy_app")
if _is_installed("backup_recommended_app"):
app_remove("backup_recommended_app")
if _is_installed("wordpress"):
app_remove("wordpress")
for app in ["legacy_app", "backup_recommended_app", "wordpress", "permissions_app"]:
if _is_installed(app):
app_remove(app)
def install_app(app, path, additionnal_args=""):
@ -198,10 +205,11 @@ def add_archive_system_from_2p4():
#
def test_backup_only_ldap():
def test_backup_only_ldap(mocker):
# Create the backup
backup_create(system=["conf_ldap"], apps=None)
with message(mocker, "backup_created"):
backup_create(system=["conf_ldap"], apps=None)
archives = backup_list()["archives"]
assert len(archives) == 1
@ -214,24 +222,22 @@ def test_backup_only_ldap():
def test_backup_system_part_that_does_not_exists(mocker):
mocker.spy(m18n, "n")
# Create the backup
with pytest.raises(YunohostError):
backup_create(system=["yolol"], apps=None)
with message(mocker, 'backup_hook_unknown', hook="doesnt_exist"):
with raiseYunohostError(mocker, "backup_nothings_done"):
backup_create(system=["doesnt_exist"], apps=None)
m18n.n.assert_any_call('backup_hook_unknown', hook="yolol")
m18n.n.assert_any_call('backup_nothings_done')
#
# System backup and restore #
#
def test_backup_and_restore_all_sys():
def test_backup_and_restore_all_sys(mocker):
# Create the backup
backup_create(system=[], apps=None)
with message(mocker, "backup_created"):
backup_create(system=[], apps=None)
archives = backup_list()["archives"]
assert len(archives) == 1
@ -247,8 +253,9 @@ def test_backup_and_restore_all_sys():
assert not os.path.exists("/etc/ssowat/conf.json")
# Restore the backup
backup_restore(name=archives[0], force=True,
system=[], apps=None)
with message(mocker, "restore_complete"):
backup_restore(name=archives[0], force=True,
system=[], apps=None)
# Check ssowat conf is back
assert os.path.exists("/etc/ssowat/conf.json")
@ -262,16 +269,18 @@ def test_backup_and_restore_all_sys():
def test_restore_system_from_Ynh2p4(monkeypatch, mocker):
# Backup current system
backup_create(system=[], apps=None)
with message(mocker, "backup_created"):
backup_create(system=[], apps=None)
archives = backup_list()["archives"]
assert len(archives) == 2
# Restore system archive from 2.4
try:
backup_restore(name=backup_list()["archives"][1],
system=[],
apps=None,
force=True)
with message(mocker, "restore_complete"):
backup_restore(name=backup_list()["archives"][1],
system=[],
apps=None,
force=True)
finally:
# Restore system as it was
backup_restore(name=backup_list()["archives"][0],
@ -298,12 +307,10 @@ def test_backup_script_failure_handling(monkeypatch, mocker):
# call with monkeypatch). We also patch m18n to check later it's been called
# with the expected error message key
monkeypatch.setattr("yunohost.backup.hook_exec", custom_hook_exec)
mocker.spy(m18n, "n")
with pytest.raises(YunohostError):
backup_create(system=None, apps=["backup_recommended_app"])
m18n.n.assert_any_call('backup_app_failed', app='backup_recommended_app')
with message(mocker, 'backup_app_failed', app='backup_recommended_app'):
with raiseYunohostError(mocker, 'backup_nothings_done'):
backup_create(system=None, apps=["backup_recommended_app"])
@pytest.mark.with_backup_recommended_app_installed
@ -319,25 +326,17 @@ def test_backup_not_enough_free_space(monkeypatch, mocker):
monkeypatch.setattr("yunohost.backup.free_space_in_directory",
custom_free_space_in_directory)
mocker.spy(m18n, "n")
with pytest.raises(YunohostError):
with raiseYunohostError(mocker, 'not_enough_disk_space'):
backup_create(system=None, apps=["backup_recommended_app"])
m18n.n.assert_any_call('not_enough_disk_space', path=ANY)
def test_backup_app_not_installed(mocker):
assert not _is_installed("wordpress")
mocker.spy(m18n, "n")
with pytest.raises(YunohostError):
backup_create(system=None, apps=["wordpress"])
m18n.n.assert_any_call("unbackup_app", app="wordpress")
m18n.n.assert_any_call('backup_nothings_done')
with message(mocker, "unbackup_app", app="wordpress"):
with raiseYunohostError(mocker, 'backup_nothings_done'):
backup_create(system=None, apps=["wordpress"])
@pytest.mark.with_backup_recommended_app_installed
@ -347,13 +346,9 @@ def test_backup_app_with_no_backup_script(mocker):
os.system("rm %s" % backup_script)
assert not os.path.exists(backup_script)
mocker.spy(m18n, "n")
with pytest.raises(YunohostError):
backup_create(system=None, apps=["backup_recommended_app"])
m18n.n.assert_any_call("backup_with_no_backup_script_for_app", app="backup_recommended_app")
m18n.n.assert_any_call('backup_nothings_done')
with message(mocker, "backup_with_no_backup_script_for_app", app="backup_recommended_app"):
with raiseYunohostError(mocker, 'backup_nothings_done'):
backup_create(system=None, apps=["backup_recommended_app"])
@pytest.mark.with_backup_recommended_app_installed
@ -363,23 +358,21 @@ def test_backup_app_with_no_restore_script(mocker):
os.system("rm %s" % restore_script)
assert not os.path.exists(restore_script)
mocker.spy(m18n, "n")
# Backuping an app with no restore script will only display a warning to the
# user...
backup_create(system=None, apps=["backup_recommended_app"])
m18n.n.assert_any_call("backup_with_no_restore_script_for_app", app="backup_recommended_app")
with message(mocker, "backup_with_no_restore_script_for_app", app="backup_recommended_app"):
backup_create(system=None, apps=["backup_recommended_app"])
@pytest.mark.clean_opt_dir
def test_backup_with_different_output_directory():
def test_backup_with_different_output_directory(mocker):
# Create the backup
backup_create(system=["conf_ssh"], apps=None,
output_directory="/opt/test_backup_output_directory",
name="backup")
with message(mocker, "backup_created"):
backup_create(system=["conf_ssh"], apps=None,
output_directory="/opt/test_backup_output_directory",
name="backup")
assert os.path.exists("/opt/test_backup_output_directory/backup.tar.gz")
@ -393,12 +386,14 @@ def test_backup_with_different_output_directory():
@pytest.mark.clean_opt_dir
def test_backup_with_no_compress():
def test_backup_with_no_compress(mocker):
# Create the backup
backup_create(system=["conf_nginx"], apps=None,
output_directory="/opt/test_backup_output_directory",
no_compress=True,
name="backup")
with message(mocker, "backup_created"):
backup_create(system=["conf_nginx"], apps=None,
output_directory="/opt/test_backup_output_directory",
no_compress=True,
name="backup")
assert os.path.exists("/opt/test_backup_output_directory/info.json")
@ -408,10 +403,11 @@ def test_backup_with_no_compress():
#
@pytest.mark.with_wordpress_archive_from_2p4
def test_restore_app_wordpress_from_Ynh2p4():
def test_restore_app_wordpress_from_Ynh2p4(mocker):
backup_restore(system=None, name=backup_list()["archives"][0],
apps=["wordpress"])
with message(mocker, "restore_complete"):
backup_restore(system=None, name=backup_list()["archives"][0],
apps=["wordpress"])
@pytest.mark.with_wordpress_archive_from_2p4
@ -423,16 +419,14 @@ def test_restore_app_script_failure_handling(monkeypatch, mocker):
raise Exception
monkeypatch.setattr("yunohost.backup.hook_exec", custom_hook_exec)
mocker.spy(m18n, "n")
assert not _is_installed("wordpress")
with pytest.raises(YunohostError):
backup_restore(system=None, name=backup_list()["archives"][0],
apps=["wordpress"])
with message(mocker, 'restore_app_failed', app='wordpress'):
with raiseYunohostError(mocker, 'restore_nothings_done'):
backup_restore(system=None, name=backup_list()["archives"][0],
apps=["wordpress"])
m18n.n.assert_any_call('restore_app_failed', app='wordpress')
m18n.n.assert_any_call('restore_nothings_done')
assert not _is_installed("wordpress")
@ -444,18 +438,13 @@ def test_restore_app_not_enough_free_space(monkeypatch, mocker):
monkeypatch.setattr("yunohost.backup.free_space_in_directory",
custom_free_space_in_directory)
mocker.spy(m18n, "n")
assert not _is_installed("wordpress")
with pytest.raises(YunohostError):
with raiseYunohostError(mocker, 'restore_not_enough_disk_space'):
backup_restore(system=None, name=backup_list()["archives"][0],
apps=["wordpress"])
m18n.n.assert_any_call('restore_not_enough_disk_space',
free_space=0,
margin=ANY,
needed_space=ANY)
assert not _is_installed("wordpress")
@ -465,13 +454,11 @@ def test_restore_app_not_in_backup(mocker):
assert not _is_installed("wordpress")
assert not _is_installed("yoloswag")
mocker.spy(m18n, "n")
with message(mocker, 'backup_archive_app_not_found', app="yoloswag"):
with raiseYunohostError(mocker, 'restore_nothings_done'):
backup_restore(system=None, name=backup_list()["archives"][0],
apps=["yoloswag"])
with pytest.raises(YunohostError):
backup_restore(system=None, name=backup_list()["archives"][0],
apps=["yoloswag"])
m18n.n.assert_any_call('backup_archive_app_not_found', app="yoloswag")
assert not _is_installed("wordpress")
assert not _is_installed("yoloswag")
@ -481,44 +468,72 @@ def test_restore_app_already_installed(mocker):
assert not _is_installed("wordpress")
backup_restore(system=None, name=backup_list()["archives"][0],
apps=["wordpress"])
assert _is_installed("wordpress")
mocker.spy(m18n, "n")
with pytest.raises(YunohostError):
with message(mocker, "restore_complete"):
backup_restore(system=None, name=backup_list()["archives"][0],
apps=["wordpress"])
m18n.n.assert_any_call('restore_already_installed_app', app="wordpress")
m18n.n.assert_any_call('restore_nothings_done')
assert _is_installed("wordpress")
with message(mocker, 'restore_already_installed_app', app="wordpress"):
with raiseYunohostError(mocker, 'restore_nothings_done'):
backup_restore(system=None, name=backup_list()["archives"][0],
apps=["wordpress"])
assert _is_installed("wordpress")
@pytest.mark.with_backup_legacy_app_installed
def test_backup_and_restore_legacy_app():
@pytest.mark.with_legacy_app_installed
def test_backup_and_restore_legacy_app(mocker):
_test_backup_and_restore_app("backup_legacy_app")
_test_backup_and_restore_app(mocker, "legacy_app")
@pytest.mark.with_backup_recommended_app_installed
def test_backup_and_restore_recommended_app():
def test_backup_and_restore_recommended_app(mocker):
_test_backup_and_restore_app("backup_recommended_app")
_test_backup_and_restore_app(mocker, "backup_recommended_app")
@pytest.mark.with_backup_recommended_app_installed_with_ynh_restore
def test_backup_and_restore_with_ynh_restore():
def test_backup_and_restore_with_ynh_restore(mocker):
_test_backup_and_restore_app("backup_recommended_app")
_test_backup_and_restore_app(mocker, "backup_recommended_app")
@pytest.mark.with_permission_app_installed
def test_backup_and_restore_permission_app():
res = user_permission_list(full=True)['permissions']
assert "permissions_app.main" in res
assert "permissions_app.admin" in res
assert "permissions_app.dev" in res
assert res['permissions_app.main']['url'] == "/"
assert res['permissions_app.admin']['url'] == "/admin"
assert res['permissions_app.dev']['url'] == "/dev"
assert res['permissions_app.main']['allowed'] == ["visitors"]
assert res['permissions_app.admin']['allowed'] == ["alice"]
assert res['permissions_app.dev']['allowed'] == []
_test_backup_and_restore_app("permissions_app")
res = user_permission_list(full=True)['permissions']
assert "permissions_app.main" in res
assert "permissions_app.admin" in res
assert "permissions_app.dev" in res
assert res['permissions_app.main']['url'] == "/"
assert res['permissions_app.admin']['url'] == "/admin"
assert res['permissions_app.dev']['url'] == "/dev"
assert res['permissions_app.main']['allowed'] == ["visitors"]
assert res['permissions_app.admin']['allowed'] == ["alice"]
assert res['permissions_app.dev']['allowed'] == []
def _test_backup_and_restore_app(app):
def _test_backup_and_restore_app(mocker, app):
# Create a backup of this app
backup_create(system=None, apps=[app])
with message(mocker, "backup_created"):
backup_create(system=None, apps=[app])
archives = backup_list()["archives"]
assert len(archives) == 1
@ -531,18 +546,18 @@ def _test_backup_and_restore_app(app):
# Uninstall the app
app_remove(app)
assert not app_is_installed(app)
assert app not in user_permission_list()['permissions']
assert app+".main" not in user_permission_list()['permissions']
# Restore the app
backup_restore(system=None, name=archives[0],
apps=[app])
with message(mocker, "restore_complete"):
backup_restore(system=None, name=archives[0],
apps=[app])
assert app_is_installed(app)
# Check permission
per_list = user_permission_list()['permissions']
assert app in per_list
assert "main" in per_list[app]
assert app+".main" in per_list
#
# Some edge cases #
@ -557,13 +572,11 @@ def test_restore_archive_with_no_json(mocker):
assert "badbackup" in backup_list()["archives"]
mocker.spy(m18n, "n")
with pytest.raises(YunohostError):
with raiseYunohostError(mocker, 'backup_invalid_archive'):
backup_restore(name="badbackup", force=True)
m18n.n.assert_any_call('backup_invalid_archive')
def test_backup_binds_are_readonly(monkeypatch):
def test_backup_binds_are_readonly(mocker, monkeypatch):
def custom_mount_and_backup(self, backup_manager):
self.manager = backup_manager
@ -584,4 +597,5 @@ def test_backup_binds_are_readonly(monkeypatch):
custom_mount_and_backup)
# Create the backup
backup_create(system=[])
with message(mocker, "backup_created"):
backup_create(system=[])

View file

@ -1,37 +1,42 @@
import requests
import pytest
from moulinette.core import MoulinetteError
from yunohost.app import app_install, app_remove, app_change_url, app_list
from yunohost.user import user_list, user_create, user_permission_list, user_delete, user_group_list, user_group_delete, user_permission_add, user_permission_remove, user_permission_clear
from yunohost.permission import permission_add, permission_update, permission_remove
from conftest import message, raiseYunohostError
from yunohost.app import app_install, app_remove, app_change_url, app_list, app_map
from yunohost.user import user_list, user_create, user_delete, \
user_group_list, user_group_delete
from yunohost.permission import user_permission_update, user_permission_list, user_permission_reset, \
permission_create, permission_delete, permission_url
from yunohost.domain import _get_maindomain
from yunohost.utils.error import YunohostError
# Get main domain
maindomain = _get_maindomain()
dummy_password = "test123Ynh"
def clean_user_groups_permission():
for u in user_list()['users']:
user_delete(u)
for g in user_group_list()['groups']:
if g != "all_users":
if g not in ["all_users", "visitors"]:
user_group_delete(g)
for a, per in user_permission_list()['permissions'].items():
if a in ['wiki', 'blog', 'site']:
for p in per:
permission_remove(a, p, force=True, sync_perm=False)
for p in user_permission_list()['permissions']:
if any(p.startswith(name) for name in ["wiki", "blog", "site", "permissions_app"]):
permission_delete(p, force=True, sync_perm=False)
def setup_function(function):
clean_user_groups_permission()
user_create("alice", "Alice", "White", "alice@" + maindomain, "test123Ynh")
user_create("bob", "Bob", "Snow", "bob@" + maindomain, "test123Ynh")
permission_add("wiki", "main", [maindomain + "/wiki"], sync_perm=False)
permission_add("blog", "main", sync_perm=False)
user_create("alice", "Alice", "White", "alice@" + maindomain, dummy_password)
user_create("bob", "Bob", "Snow", "bob@" + maindomain, dummy_password)
permission_create("wiki.main", url="/", sync_perm=False)
permission_create("blog.main", sync_perm=False)
user_permission_update("blog.main", remove="all_users", add="alice")
user_permission_add(["blog"], "main", group="alice")
def teardown_function(function):
clean_user_groups_permission()
@ -39,6 +44,11 @@ def teardown_function(function):
app_remove("permissions_app")
except:
pass
try:
app_remove("legacy_app")
except:
pass
@pytest.fixture(autouse=True)
def check_LDAP_db_integrity_call():
@ -46,6 +56,7 @@ def check_LDAP_db_integrity_call():
yield
check_LDAP_db_integrity()
def check_LDAP_db_integrity():
# Here we check that all attributes in all object are sychronized.
# Here is the list of attributes per object:
@ -57,7 +68,7 @@ def check_LDAP_db_integrity():
# One part should be done automatically by the "memberOf" overlay of LDAP.
# The other part is done by the the "permission_sync_to_user" function of the permission module
from yunohost.utils.ldap import _get_ldap_interface
from yunohost.utils.ldap import _get_ldap_interface, _ldap_path_extract
ldap = _get_ldap_interface()
user_search = ldap.search('ou=users,dc=yunohost,dc=org',
@ -76,161 +87,197 @@ def check_LDAP_db_integrity():
for user in user_search:
user_dn = 'uid=' + user['uid'][0] + ',ou=users,dc=yunohost,dc=org'
group_list = [m.split("=")[1].split(",")[0] for m in user['memberOf']]
permission_list = []
if 'permission' in user:
permission_list = [m.split("=")[1].split(",")[0] for m in user['permission']]
group_list = [_ldap_path_extract(m, "cn") for m in user['memberOf']]
permission_list = [_ldap_path_extract(m, "cn") for m in user.get('permission', [])]
# This user's DN sould be found in all groups it is a member of
for group in group_list:
assert user_dn in group_map[group]['member']
# This user's DN should be found in all perms it has access to
for permission in permission_list:
assert user_dn in permission_map[permission]['inheritPermission']
for permission in permission_search:
permission_dn = 'cn=' + permission['cn'][0] + ',ou=permission,dc=yunohost,dc=org'
user_list = []
group_list = []
if 'inheritPermission' in permission:
user_list = [m.split("=")[1].split(",")[0] for m in permission['inheritPermission']]
assert set(user_list) == set(permission['memberUid'])
if 'groupPermission' in permission:
group_list = [m.split("=")[1].split(",")[0] for m in permission['groupPermission']]
# inheritPermission uid's should match memberUids
user_list = [_ldap_path_extract(m, "uid") for m in permission.get('inheritPermission', [])]
assert set(user_list) == set(permission.get('memberUid', []))
# This perm's DN should be found on all related users it is related to
for user in user_list:
assert permission_dn in user_map[user]['permission']
# Same for groups : we should find the permission's DN for all related groups
group_list = [_ldap_path_extract(m, "cn") for m in permission.get('groupPermission', [])]
for group in group_list:
assert permission_dn in group_map[group]['permission']
if 'member' in group_map[group]:
user_list_in_group = [m.split("=")[1].split(",")[0] for m in group_map[group]['member']]
assert set(user_list_in_group) <= set(user_list)
# The list of user in the group should be a subset of all users related to the current permission
users_in_group = [_ldap_path_extract(m, "uid") for m in group_map[group].get("member", [])]
assert set(users_in_group) <= set(user_list)
for group in group_search:
group_dn = 'cn=' + group['cn'][0] + ',ou=groups,dc=yunohost,dc=org'
user_list = []
permission_list = []
if 'member' in group:
user_list = [m.split("=")[1].split(",")[0] for m in group['member']]
if group['cn'][0] in user_list:
# If it's the main group of the user it's normal that it is not in the memberUid
g_list = list(user_list)
g_list.remove(group['cn'][0])
if 'memberUid' in group:
assert set(g_list) == set(group['memberUid'])
else:
assert g_list == []
else:
assert set(user_list) == set(group['memberUid'])
if 'permission' in group:
permission_list = [m.split("=")[1].split(",")[0] for m in group['permission']]
user_list = [_ldap_path_extract(m, "uid") for m in group.get("member", [])]
# For primary groups, we should find that :
# - len(user_list) is 1 (a primary group has only 1 member)
# - the group name should be an existing yunohost user
# - memberUid is empty (meaning no other member than the corresponding user)
if group['cn'][0] in user_list:
assert len(user_list) == 1
assert group["cn"][0] in user_map
assert group.get('memberUid', []) == []
# Otherwise, user_list and memberUid should have the same content
else:
assert set(user_list) == set(group.get('memberUid', []))
# For all users members, this group should be in the "memberOf" on the other side
for user in user_list:
assert group_dn in user_map[user]['memberOf']
# For all the permissions of this group, the group should be among the "groupPermission" on the other side
permission_list = [_ldap_path_extract(m, "cn") for m in group.get('permission', [])]
for permission in permission_list:
assert group_dn in permission_map[permission]['groupPermission']
if 'inheritPermission' in permission_map:
allowed_user_list = [m.split("=")[1].split(",")[0] for m in permission_map[permission]['inheritPermission']]
assert set(user_list) <= set(allowed_user_list)
# And the list of user of this group (user_list) should be a subset of all allowed users for this perm...
allowed_user_list = [_ldap_path_extract(m, "uid") for m in permission_map[permission].get('inheritPermission', [])]
assert set(user_list) <= set(allowed_user_list)
def check_permission_for_apps():
# We check that the for each installed apps we have at last the "main" permission
# and we don't have any permission linked to no apps. The only exception who is not liked to an app
# is mail, metronome, and sftp
# is mail, xmpp, and sftp
from yunohost.utils.ldap import _get_ldap_interface
ldap = _get_ldap_interface()
permission_search = ldap.search('ou=permission,dc=yunohost,dc=org',
'(objectclass=permissionYnh)',
['cn', 'groupPermission', 'inheritPermission', 'memberUid'])
app_perms = user_permission_list(ignore_system_perms=True)["permissions"].keys()
# Keep only the prefix so that
# ["foo.main", "foo.pwet", "bar.main"]
# becomes
# {"bar", "foo"}
# and compare this to the list of installed apps ...
app_perms_prefix = set(p.split(".")[0] for p in app_perms)
installed_apps = {app['id'] for app in app_list(installed=True)['apps']}
permission_list_set = {permission['cn'][0].split(".")[1] for permission in permission_search}
extra_service_permission = set(['mail', 'metronome'])
if 'sftp' in permission_list_set:
extra_service_permission.add('sftp')
assert installed_apps == permission_list_set - extra_service_permission
assert installed_apps == app_perms_prefix
def can_access_webpage(webpath, logged_as=None):
webpath = webpath.rstrip("/")
sso_url = "https://" + maindomain + "/yunohost/sso/"
# Anonymous access
if not logged_as:
r = requests.get(webpath, verify=False)
# Login as a user using dummy password
else:
with requests.Session() as session:
session.post(sso_url,
data={"user": logged_as,
"password": dummy_password},
headers={"Referer": sso_url,
"Content-Type": "application/x-www-form-urlencoded"},
verify=False)
# We should have some cookies related to authentication now
assert session.cookies
r = session.get(webpath, verify=False)
# If we can't access it, we got redirected to the SSO
return not r.url.startswith(sso_url)
#
# List functions
#
def test_list_permission():
res = user_permission_list()['permissions']
def test_permission_list():
res = user_permission_list(full=True)['permissions']
assert "wiki" in res
assert "main" in res['wiki']
assert "blog" in res
assert "main" in res['blog']
assert "mail" in res
assert "main" in res['mail']
assert "metronome" in res
assert "main" in res['metronome']
assert ["all_users"] == res['wiki']['main']['allowed_groups']
assert ["alice"] == res['blog']['main']['allowed_groups']
assert set(["alice", "bob"]) == set(res['wiki']['main']['allowed_users'])
assert ["alice"] == res['blog']['main']['allowed_users']
assert [maindomain + "/wiki"] == res['wiki']['main']['URL']
assert "wiki.main" in res
assert "blog.main" in res
assert "mail.main" in res
assert "xmpp.main" in res
assert res['wiki.main']['allowed'] == ["all_users"]
assert res['blog.main']['allowed'] == ["alice"]
assert set(res['wiki.main']['corresponding_users']) == set(["alice", "bob"])
assert res['blog.main']['corresponding_users'] == ["alice"]
assert res['wiki.main']['url'] == "/"
#
# Create - Remove functions
#
def test_add_permission_1():
permission_add("site", "test")
def test_permission_create_main(mocker):
with message(mocker, "permission_created", permission="site.main"):
permission_create("site.main")
res = user_permission_list(full=True)['permissions']
assert "site.main" in res
assert res['site.main']['allowed'] == ["all_users"]
assert set(res['site.main']['corresponding_users']) == set(["alice", "bob"])
def test_permission_create_extra(mocker):
with message(mocker, "permission_created", permission="site.test"):
permission_create("site.test")
res = user_permission_list(full=True)['permissions']
assert "site.test" in res
# all_users is only enabled by default on .main perms
assert "all_users" not in res['site.test']['allowed']
assert res['site.test']['corresponding_users'] == []
def test_permission_create_with_allowed():
permission_create("site.test", allowed=["alice"])
res = user_permission_list(full=True)['permissions']
assert "site.test" in res
assert res['site.test']['allowed'] == ["alice"]
def test_permission_delete(mocker):
with message(mocker, "permission_deleted", permission="wiki.main"):
permission_delete("wiki.main", force=True)
res = user_permission_list()['permissions']
assert "site" in res
assert "test" in res['site']
assert "all_users" in res['site']['test']['allowed_groups']
assert set(["alice", "bob"]) == set(res['site']['test']['allowed_users'])
def test_add_permission_2():
permission_add("site", "main", default_allow=False)
res = user_permission_list()['permissions']
assert "site" in res
assert "main" in res['site']
assert [] == res['site']['main']['allowed_groups']
assert [] == res['site']['main']['allowed_users']
def test_remove_permission():
permission_remove("wiki", "main", force=True)
res = user_permission_list()['permissions']
assert "wiki" not in res
assert "wiki.main" not in res
#
# Error on create - remove function
#
def test_add_bad_permission():
# Create permission with same name
with pytest.raises(YunohostError):
permission_add("wiki", "main")
def test_remove_bad_permission():
# Remove not existant permission
with pytest.raises(MoulinetteError):
permission_remove("non_exit", "main", force=True)
def test_permission_create_already_existing(mocker):
with raiseYunohostError(mocker, "permission_already_exist"):
permission_create("wiki.main")
def test_permission_delete_doesnt_existing(mocker):
with raiseYunohostError(mocker, "permission_not_found"):
permission_delete("doesnt.exist", force=True)
res = user_permission_list()['permissions']
assert "wiki" in res
assert "main" in res['wiki']
assert "blog" in res
assert "main" in res['blog']
assert "mail" in res
assert "main" in res ['mail']
assert "metronome" in res
assert "main" in res['metronome']
assert "wiki.main" in res
assert "blog.main" in res
assert "mail.main" in res
assert "xmpp.main" in res
def test_remove_main_permission():
with pytest.raises(YunohostError):
permission_remove("blog", "main")
def test_permission_delete_main_without_force(mocker):
with raiseYunohostError(mocker, "permission_cannot_remove_main"):
permission_delete("blog.main")
res = user_permission_list()['permissions']
assert "mail" in res
assert "main" in res['mail']
assert "blog.main" in res
#
# Update functions
@ -238,182 +285,222 @@ def test_remove_main_permission():
# user side functions
def test_allow_first_group():
# Remove permission to all_users and define per users
user_permission_add(["wiki"], "main", group="alice")
res = user_permission_list()['permissions']
assert ['alice'] == res['wiki']['main']['allowed_users']
assert ['alice'] == res['wiki']['main']['allowed_groups']
def test_permission_add_group(mocker):
with message(mocker, "permission_updated", permission="wiki.main"):
user_permission_update("wiki.main", add="alice")
def test_allow_other_group():
# Allow new user in a permission
user_permission_add(["blog"], "main", group="bob")
res = user_permission_list(full=True)['permissions']
assert set(res['wiki.main']['allowed']) == set(["all_users", "alice"])
assert set(res['wiki.main']['corresponding_users']) == set(["alice", "bob"])
res = user_permission_list()['permissions']
assert set(["alice", "bob"]) == set(res['blog']['main']['allowed_users'])
assert set(["alice", "bob"]) == set(res['blog']['main']['allowed_groups'])
def test_disallow_group_1():
# Disallow a user in a permission
user_permission_remove(["blog"], "main", group="alice")
def test_permission_remove_group(mocker):
with message(mocker, "permission_updated", permission="blog.main"):
user_permission_update("blog.main", remove="alice")
res = user_permission_list()['permissions']
assert [] == res['blog']['main']['allowed_users']
assert [] == res['blog']['main']['allowed_groups']
res = user_permission_list(full=True)['permissions']
assert res['blog.main']['allowed'] == []
assert res['blog.main']['corresponding_users'] == []
def test_allow_group_1():
# Allow a user when he is already allowed
user_permission_add(["blog"], "main", group="alice")
res = user_permission_list()['permissions']
assert ["alice"] == res['blog']['main']['allowed_users']
assert ["alice"] == res['blog']['main']['allowed_groups']
def test_permission_add_and_remove_group(mocker):
with message(mocker, "permission_updated", permission="wiki.main"):
user_permission_update("wiki.main", add="alice", remove="all_users")
def test_disallow_group_1():
# Disallow a user when he is already disallowed
user_permission_remove(["blog"], "main", group="bob")
res = user_permission_list(full=True)['permissions']
assert res['wiki.main']['allowed'] == ["alice"]
assert res['wiki.main']['corresponding_users'] == ["alice"]
res = user_permission_list()['permissions']
assert ["alice"] == res['blog']['main']['allowed_users']
assert ["alice"] == res['blog']['main']['allowed_groups']
def test_reset_permission():
def test_permission_add_group_already_allowed(mocker):
with message(mocker, "permission_already_allowed", permission="blog.main", group="alice"):
user_permission_update("blog.main", add="alice")
res = user_permission_list(full=True)['permissions']
assert res['blog.main']['allowed'] == ["alice"]
assert res['blog.main']['corresponding_users'] == ["alice"]
def test_permission_remove_group_already_not_allowed(mocker):
with message(mocker, "permission_already_disallowed", permission="blog.main", group="bob"):
user_permission_update("blog.main", remove="bob")
res = user_permission_list(full=True)['permissions']
assert res['blog.main']['allowed'] == ["alice"]
assert res['blog.main']['corresponding_users'] == ["alice"]
def test_permission_reset(mocker):
with message(mocker, "permission_updated", permission="blog.main"):
user_permission_reset("blog.main")
res = user_permission_list(full=True)['permissions']
assert res['blog.main']['allowed'] == ["all_users"]
assert set(res['blog.main']['corresponding_users']) == set(["alice", "bob"])
def test_permission_reset_idempotency():
# Reset permission
user_permission_clear(["blog"], "main")
user_permission_reset("blog.main")
user_permission_reset("blog.main")
res = user_permission_list()['permissions']
assert set(["alice", "bob"]) == set(res['blog']['main']['allowed_users'])
assert ["all_users"] == res['blog']['main']['allowed_groups']
res = user_permission_list(full=True)['permissions']
assert res['blog.main']['allowed'] == ["all_users"]
assert set(res['blog.main']['corresponding_users']) == set(["alice", "bob"])
# internal functions
def test_add_url_1():
# Add URL in permission which hasn't any URL defined
permission_update("blog", "main", add_url=[maindomain + "/testA"])
def test_permission_reset_idempotency():
# Reset permission
user_permission_reset("blog.main")
user_permission_reset("blog.main")
res = user_permission_list()['permissions']
assert [maindomain + "/testA"] == res['blog']['main']['URL']
res = user_permission_list(full=True)['permissions']
assert res['blog.main']['allowed'] == ["all_users"]
assert set(res['blog.main']['corresponding_users']) == set(["alice", "bob"])
def test_add_url_2():
# Add a second URL in a permission
permission_update("wiki", "main", add_url=[maindomain + "/testA"])
res = user_permission_list()['permissions']
assert set([maindomain + "/testA", maindomain + "/wiki"]) == set(res['wiki']['main']['URL'])
def test_remove_url_1():
permission_update("wiki", "main", remove_url=[maindomain + "/wiki"])
res = user_permission_list()['permissions']
assert 'URL' not in res['wiki']['main']
def test_add_url_3():
# Add a url already added
permission_update("wiki", "main", add_url=[maindomain + "/wiki"])
res = user_permission_list()['permissions']
assert [maindomain + "/wiki"] == res['wiki']['main']['URL']
def test_remove_url_2():
# Remove a url not added (with a permission which contain some URL)
permission_update("wiki", "main", remove_url=[maindomain + "/not_exist"])
res = user_permission_list()['permissions']
assert [maindomain + "/wiki"] == res['wiki']['main']['URL']
def test_remove_url_2():
# Remove a url not added (with a permission which contain no URL)
permission_update("blog", "main", remove_url=[maindomain + "/not_exist"])
res = user_permission_list()['permissions']
assert 'URL' not in res['blog']['main']
#
# Error on update function
#
def test_disallow_bad_group_1():
# Disallow a group when the group all_users is allowed
with pytest.raises(YunohostError):
user_permission_remove("wiki", "main", group="alice")
res = user_permission_list()['permissions']
assert ["all_users"] == res['wiki']['main']['allowed_groups']
assert set(["alice", "bob"]) == set(res['wiki']['main']['allowed_users'])
def test_permission_add_group_that_doesnt_exist(mocker):
with raiseYunohostError(mocker, "group_unknown"):
user_permission_update("blog.main", add="doesnt_exist")
def test_allow_bad_user():
# Allow a non existant group
with pytest.raises(YunohostError):
user_permission_add(["blog"], "main", group="not_exist")
res = user_permission_list(full=True)['permissions']
assert res['blog.main']['allowed'] == ["alice"]
assert res['blog.main']['corresponding_users'] == ["alice"]
res = user_permission_list()['permissions']
assert ["alice"] == res['blog']['main']['allowed_groups']
assert ["alice"] == res['blog']['main']['allowed_users']
def test_disallow_bad_group_2():
# Disallow a non existant group
with pytest.raises(YunohostError):
user_permission_remove(["blog"], "main", group="not_exist")
def test_permission_update_permission_that_doesnt_exist(mocker):
with raiseYunohostError(mocker, "permission_not_found"):
user_permission_update("doesnt.exist", add="alice")
res = user_permission_list()['permissions']
assert ["alice"] == res['blog']['main']['allowed_groups']
assert ["alice"] == res['blog']['main']['allowed_users']
def test_allow_bad_permission_1():
# Allow a user to a non existant permission
with pytest.raises(YunohostError):
user_permission_add(["wiki"], "not_exit", group="alice")
# Permission url management
def test_allow_bad_permission_2():
# Allow a user to a non existant permission
with pytest.raises(YunohostError):
user_permission_add(["not_exit"], "main", group="alice")
def test_permission_redefine_url():
permission_url("blog.main", url="/pwet")
res = user_permission_list(full=True)['permissions']
assert res["blog.main"]["url"] == "/pwet"
def test_permission_remove_url():
permission_url("blog.main", url=None)
res = user_permission_list(full=True)['permissions']
assert res["blog.main"]["url"] is None
#
# Application interaction
#
def test_install_app():
def test_permission_app_install():
app_install("./tests/apps/permissions_app_ynh",
args="domain=%s&path=%s&admin=%s" % (maindomain, "/urlpermissionapp", "alice"), force=True)
args="domain=%s&path=%s&is_public=0&admin=%s" % (maindomain, "/urlpermissionapp", "alice"), force=True)
res = user_permission_list()['permissions']
assert "permissions_app" in res
assert "main" in res['permissions_app']
assert [maindomain + "/urlpermissionapp"] == res['permissions_app']['main']['URL']
assert [maindomain + "/urlpermissionapp/admin"] == res['permissions_app']['admin']['URL']
assert [maindomain + "/urlpermissionapp/dev"] == res['permissions_app']['dev']['URL']
res = user_permission_list(full=True)['permissions']
assert "permissions_app.main" in res
assert "permissions_app.admin" in res
assert "permissions_app.dev" in res
assert res['permissions_app.main']['url'] == "/"
assert res['permissions_app.admin']['url'] == "/admin"
assert res['permissions_app.dev']['url'] == "/dev"
assert ["all_users"] == res['permissions_app']['main']['allowed_groups']
assert set(["alice", "bob"]) == set(res['permissions_app']['main']['allowed_users'])
assert res['permissions_app.main']['allowed'] == ["all_users"]
assert set(res['permissions_app.main']['corresponding_users']) == set(["alice", "bob"])
assert ["alice"] == res['permissions_app']['admin']['allowed_groups']
assert ["alice"] == res['permissions_app']['admin']['allowed_users']
assert res['permissions_app.admin']['allowed'] == ["alice"]
assert res['permissions_app.admin']['corresponding_users'] == ["alice"]
assert ["all_users"] == res['permissions_app']['dev']['allowed_groups']
assert set(["alice", "bob"]) == set(res['permissions_app']['dev']['allowed_users'])
assert res['permissions_app.dev']['allowed'] == []
assert set(res['permissions_app.dev']['corresponding_users']) == set()
def test_remove_app():
# Check that we get the right stuff in app_map, which is used to generate the ssowatconf
assert maindomain + "/urlpermissionapp" in app_map(user="alice").keys()
user_permission_update("permissions_app.main", remove="all_users", add="bob")
assert maindomain + "/urlpermissionapp" not in app_map(user="alice").keys()
assert maindomain + "/urlpermissionapp" in app_map(user="bob").keys()
def test_permission_app_remove():
app_install("./tests/apps/permissions_app_ynh",
args="domain=%s&path=%s&admin=%s" % (maindomain, "/urlpermissionapp", "alice"), force=True)
args="domain=%s&path=%s&is_public=0&admin=%s" % (maindomain, "/urlpermissionapp", "alice"), force=True)
app_remove("permissions_app")
res = user_permission_list()['permissions']
assert "permissions_app" not in res
# Check all permissions for this app got deleted
res = user_permission_list(full=True)['permissions']
assert not any(p.startswith("permissions_app.") for p in res.keys())
def test_change_url():
def test_permission_app_change_url():
app_install("./tests/apps/permissions_app_ynh",
args="domain=%s&path=%s&admin=%s" % (maindomain, "/urlpermissionapp", "alice"), force=True)
res = user_permission_list()['permissions']
assert [maindomain + "/urlpermissionapp"] == res['permissions_app']['main']['URL']
assert [maindomain + "/urlpermissionapp/admin"] == res['permissions_app']['admin']['URL']
assert [maindomain + "/urlpermissionapp/dev"] == res['permissions_app']['dev']['URL']
# FIXME : should rework this test to look for differences in the generated app map / app tiles ...
res = user_permission_list(full=True)['permissions']
assert res['permissions_app.main']['url'] == "/"
assert res['permissions_app.admin']['url'] == "/admin"
assert res['permissions_app.dev']['url'] == "/dev"
app_change_url("permissions_app", maindomain, "/newchangeurl")
res = user_permission_list()['permissions']
assert [maindomain + "/newchangeurl"] == res['permissions_app']['main']['URL']
assert [maindomain + "/newchangeurl/admin"] == res['permissions_app']['admin']['URL']
assert [maindomain + "/newchangeurl/dev"] == res['permissions_app']['dev']['URL']
res = user_permission_list(full=True)['permissions']
assert res['permissions_app.main']['url'] == "/"
assert res['permissions_app.admin']['url'] == "/admin"
assert res['permissions_app.dev']['url'] == "/dev"
def test_permission_app_propagation_on_ssowat():
app_install("./tests/apps/permissions_app_ynh",
args="domain=%s&path=%s&is_public=1&admin=%s" % (maindomain, "/urlpermissionapp", "alice"), force=True)
res = user_permission_list(full=True)['permissions']
assert res['permissions_app.main']['allowed'] == ["visitors"]
app_webroot = "https://%s/urlpermissionapp" % maindomain
assert can_access_webpage(app_webroot, logged_as=None)
assert can_access_webpage(app_webroot, logged_as="alice")
user_permission_update("permissions_app.main", remove="visitors", add="bob")
res = user_permission_list(full=True)['permissions']
assert not can_access_webpage(app_webroot, logged_as=None)
assert not can_access_webpage(app_webroot, logged_as="alice")
assert can_access_webpage(app_webroot, logged_as="bob")
# Test admin access, as configured during install, only alice should be able to access it
# alice gotta be allowed on the main permission to access the admin tho
user_permission_update("permissions_app.main", remove="bob", add="all_users")
assert not can_access_webpage(app_webroot+"/admin", logged_as=None)
assert can_access_webpage(app_webroot+"/admin", logged_as="alice")
assert not can_access_webpage(app_webroot+"/admin", logged_as="bob")
def test_permission_legacy_app_propagation_on_ssowat():
app_install("./tests/apps/legacy_app_ynh",
args="domain=%s&path=%s" % (maindomain, "/legacy"), force=True)
# App is configured as public by default using the legacy unprotected_uri mechanics
# It should automatically be migrated during the install
res = user_permission_list(full=True)['permissions']
assert res['legacy_app.main']['allowed'] == ["visitors"]
app_webroot = "https://%s/legacy" % maindomain
assert can_access_webpage(app_webroot, logged_as=None)
assert can_access_webpage(app_webroot, logged_as="alice")
# Try to update the permission and check that permissions are still consistent
user_permission_update("legacy_app.main", remove="visitors", add="bob")
assert not can_access_webpage(app_webroot, logged_as=None)
assert not can_access_webpage(app_webroot, logged_as="alice")
assert can_access_webpage(app_webroot, logged_as="bob")

View file

@ -1,22 +1,25 @@
import pytest
from moulinette.core import MoulinetteError
from yunohost.user import user_list, user_info, user_group_list, user_create, user_delete, user_update, user_group_add, user_group_delete, user_group_update, user_group_info
from conftest import message, raiseYunohostError
from yunohost.user import user_list, user_info, user_create, user_delete, user_update, \
user_group_list, user_group_create, user_group_delete, user_group_update
from yunohost.domain import _get_maindomain
from yunohost.utils.error import YunohostError
from yunohost.tests.test_permission import check_LDAP_db_integrity
# Get main domain
maindomain = _get_maindomain()
def clean_user_groups():
for u in user_list()['users']:
user_delete(u)
for g in user_group_list()['groups']:
if g != "all_users":
if g not in ["all_users", "visitors"]:
user_group_delete(g)
def setup_function(function):
clean_user_groups()
@ -24,14 +27,16 @@ def setup_function(function):
user_create("bob", "Bob", "Snow", "bob@" + maindomain, "test123Ynh")
user_create("jack", "Jack", "Black", "jack@" + maindomain, "test123Ynh")
user_group_add("dev")
user_group_add("apps")
user_group_update("dev", add_user=["alice"])
user_group_update("apps", add_user=["bob"])
user_group_create("dev")
user_group_create("apps")
user_group_update("dev", add=["alice"])
user_group_update("apps", add=["bob"])
def teardown_function(function):
clean_user_groups()
@pytest.fixture(autouse=True)
def check_LDAP_db_integrity_call():
check_LDAP_db_integrity()
@ -42,6 +47,7 @@ def check_LDAP_db_integrity_call():
# List functions
#
def test_list_users():
res = user_list()['users']
@ -49,6 +55,7 @@ def test_list_users():
assert "bob" in res
assert "jack" in res
def test_list_groups():
res = user_group_list()['groups']
@ -65,8 +72,11 @@ def test_list_groups():
# Create - Remove functions
#
def test_create_user():
user_create("albert", "Albert", "Good", "alber@" + maindomain, "test123Ynh")
def test_create_user(mocker):
with message(mocker, "user_created"):
user_create("albert", "Albert", "Good", "alber@" + maindomain, "test123Ynh")
group_res = user_group_list()['groups']
assert "albert" in user_list()['users']
@ -74,23 +84,33 @@ def test_create_user():
assert "albert" in group_res['albert']['members']
assert "albert" in group_res['all_users']['members']
def test_del_user():
user_delete("alice")
def test_del_user(mocker):
with message(mocker, "user_deleted"):
user_delete("alice")
group_res = user_group_list()['groups']
assert "alice" not in user_list()
assert "alice" not in group_res
assert "alice" not in group_res['all_users']['members']
def test_add_group():
user_group_add("adminsys")
def test_create_group(mocker):
with message(mocker, "group_created", group="adminsys"):
user_group_create("adminsys")
group_res = user_group_list()['groups']
assert "adminsys" in group_res
assert "members" not in group_res['adminsys']
assert "members" in group_res['adminsys'].keys()
assert group_res["adminsys"]["members"] == []
def test_del_group():
user_group_delete("dev")
def test_del_group(mocker):
with message(mocker, "group_deleted", group="dev"):
user_group_delete("dev")
group_res = user_group_list()['groups']
assert "dev" not in group_res
@ -99,112 +119,129 @@ def test_del_group():
# Error on create / remove function
#
def test_add_bad_user_1():
# Check email already exist
with pytest.raises(MoulinetteError):
def test_create_user_with_mail_address_already_taken(mocker):
with raiseYunohostError(mocker, "user_creation_failed"):
user_create("alice2", "Alice", "White", "alice@" + maindomain, "test123Ynh")
def test_add_bad_user_2():
# Check to short password
with pytest.raises(MoulinetteError):
def test_create_user_with_password_too_simple(mocker):
with raiseYunohostError(mocker, "password_listed"):
user_create("other", "Alice", "White", "other@" + maindomain, "12")
def test_add_bad_user_3():
# Check user already exist
with pytest.raises(MoulinetteError):
def test_create_user_already_exists(mocker):
with raiseYunohostError(mocker, "user_already_exists"):
user_create("alice", "Alice", "White", "other@" + maindomain, "test123Ynh")
def test_del_bad_user_1():
# Check user not found
with pytest.raises(MoulinetteError):
user_delete("not_exit")
def test_add_bad_group_1():
def test_update_user_with_mail_address_already_taken(mocker):
with raiseYunohostError(mocker, "user_update_failed"):
user_update("bob", add_mailalias="alice@" + maindomain)
def test_del_user_that_does_not_exist(mocker):
with raiseYunohostError(mocker, "user_unknown"):
user_delete("doesnt_exist")
def test_create_group_all_users(mocker):
# Check groups already exist with special group "all_users"
with pytest.raises(YunohostError):
user_group_add("all_users")
with raiseYunohostError(mocker, "group_already_exist"):
user_group_create("all_users")
def test_add_bad_group_2():
# Check groups already exist (for standard groups)
with pytest.raises(MoulinetteError):
user_group_add("dev")
def test_del_bad_group_1():
# Check not allowed to remove this groups
with pytest.raises(YunohostError):
def test_create_group_already_exists(mocker):
# Check groups already exist (regular groups)
with raiseYunohostError(mocker, "group_already_exist"):
user_group_create("dev")
def test_del_group_all_users(mocker):
with raiseYunohostError(mocker, "group_cannot_be_deleted"):
user_group_delete("all_users")
def test_del_bad_group_2():
# Check groups not found
with pytest.raises(MoulinetteError):
user_group_delete("not_exit")
def test_del_group_that_does_not_exist(mocker):
with raiseYunohostError(mocker, "group_unknown"):
user_group_delete("doesnt_exist")
#
# Update function
#
def test_update_user_1():
user_update("alice", firstname="NewName", lastname="NewLast")
def test_update_user(mocker):
with message(mocker, "user_updated"):
user_update("alice", firstname="NewName", lastname="NewLast")
info = user_info("alice")
assert "NewName" == info['firstname']
assert "NewLast" == info['lastname']
assert info['firstname'] == "NewName"
assert info['lastname'] == "NewLast"
def test_update_group_1():
user_group_update("dev", add_user=["bob"])
def test_update_group_add_user(mocker):
with message(mocker, "group_updated", group="dev"):
user_group_update("dev", add=["bob"])
group_res = user_group_list()['groups']
assert set(["alice", "bob"]) == set(group_res['dev']['members'])
assert set(group_res['dev']['members']) == set(["alice", "bob"])
def test_update_group_2():
# Try to add a user in a group when the user is already in
user_group_update("apps", add_user=["bob"])
def test_update_group_add_user_already_in(mocker):
with message(mocker, "group_user_already_in_group", user="bob", group="apps"):
user_group_update("apps", add=["bob"])
group_res = user_group_list()['groups']
assert ["bob"] == group_res['apps']['members']
assert group_res['apps']['members'] == ["bob"]
def test_update_group_3():
# Try to remove a user in a group
user_group_update("apps", remove_user=["bob"])
def test_update_group_remove_user(mocker):
with message(mocker, "group_updated", group="apps"):
user_group_update("apps", remove=["bob"])
group_res = user_group_list()['groups']
assert "members" not in group_res['apps']
assert group_res['apps']['members'] == []
def test_update_group_4():
# Try to remove a user in a group when it is not already in
user_group_update("apps", remove_user=["jack"])
def test_update_group_remove_user_not_already_in(mocker):
with message(mocker, "group_user_not_in_group", user="jack", group="apps"):
user_group_update("apps", remove=["jack"])
group_res = user_group_list()['groups']
assert ["bob"] == group_res['apps']['members']
assert group_res['apps']['members'] == ["bob"]
#
# Error on update functions
#
def test_bad_update_user_1():
# Check user not found
with pytest.raises(YunohostError):
user_update("not_exit", firstname="NewName", lastname="NewLast")
def test_update_user_that_doesnt_exist(mocker):
with raiseYunohostError(mocker, "user_unknown"):
user_update("doesnt_exist", firstname="NewName", lastname="NewLast")
def bad_update_group_1():
# Check groups not found
with pytest.raises(YunohostError):
user_group_update("not_exit", add_user=["alice"])
def test_update_group_that_doesnt_exist(mocker):
with raiseYunohostError(mocker, "group_unknown"):
user_group_update("doesnt_exist", add=["alice"])
def test_bad_update_group_2():
# Check remove user in groups "all_users" not allowed
with pytest.raises(YunohostError):
user_group_update("all_users", remove_user=["alice"])
def test_bad_update_group_3():
# Check remove user in it own group not allowed
with pytest.raises(YunohostError):
user_group_update("alice", remove_user=["alice"])
def test_update_group_all_users_manually(mocker):
with raiseYunohostError(mocker, "group_cannot_edit_all_users"):
user_group_update("all_users", remove=["alice"])
def test_bad_update_group_1():
# Check add bad user in group
with pytest.raises(YunohostError):
user_group_update("dev", add_user=["not_exist"])
assert "alice" in user_group_list()["groups"]["all_users"]["members"]
assert "not_exist" not in user_group_list()["groups"]["dev"]
def test_update_group_primary_manually(mocker):
with raiseYunohostError(mocker, "group_cannot_edit_primary_group"):
user_group_update("alice", remove=["alice"])
assert "alice" in user_group_list()["groups"]["alice"]["members"]
def test_update_group_add_user_that_doesnt_exist(mocker):
with raiseYunohostError(mocker, "user_unknown"):
user_group_update("dev", add=["doesnt_exist"])
assert "doesnt_exist" not in user_group_list()["groups"]["dev"]["members"]

View file

@ -350,25 +350,17 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False,
os.system('hostname yunohost.yunohost.org')
# Add a temporary SSOwat rule to redirect SSO to admin page
try:
with open('/etc/ssowat/conf.json.persistent') as json_conf:
ssowat_conf = json.loads(str(json_conf.read()))
except ValueError as e:
raise YunohostError('ssowat_persistent_conf_read_error', error=str(e))
except IOError:
if not os.path.exists('/etc/ssowat/conf.json.persistent'):
ssowat_conf = {}
else:
ssowat_conf = read_json('/etc/ssowat/conf.json.persistent')
if 'redirected_urls' not in ssowat_conf:
ssowat_conf['redirected_urls'] = {}
ssowat_conf['redirected_urls']['/'] = domain + '/yunohost/admin'
try:
with open('/etc/ssowat/conf.json.persistent', 'w+') as f:
json.dump(ssowat_conf, f, sort_keys=True, indent=4)
except IOError as e:
raise YunohostError('ssowat_persistent_conf_write_error', error=str(e))
write_to_json('/etc/ssowat/conf.json.persistent', ssowat_conf)
os.system('chmod 644 /etc/ssowat/conf.json.persistent')
# Create SSL CA
@ -584,10 +576,7 @@ def tools_upgrade(operation_logger, apps=None, system=False):
upgradable_apps = [app["id"] for app in _list_upgradable_apps()]
if not upgradable_apps:
logger.info(m18n.n("app_no_upgrade"))
return
elif len(apps) and all(app not in upgradable_apps for app in apps):
if not upgradable_apps or (len(apps) and all(app not in upgradable_apps for app in apps)):
logger.info(m18n.n("apps_already_up_to_date"))
return
@ -619,8 +608,8 @@ def tools_upgrade(operation_logger, apps=None, system=False):
# randomly from yunohost itself... upgrading them is likely to
critical_packages = ("moulinette", "yunohost", "yunohost-admin", "ssowat", "python")
critical_packages_upgradable = [p for p in upgradables if p["name"] in critical_packages]
noncritical_packages_upgradable = [p for p in upgradables if p["name"] not in critical_packages]
critical_packages_upgradable = [p["name"] for p in upgradables if p["name"] in critical_packages]
noncritical_packages_upgradable = [p["name"] for p in upgradables if p["name"] not in critical_packages]
# Prepare dist-upgrade command
dist_upgrade = "DEBIAN_FRONTEND=noninteractive"
@ -651,13 +640,16 @@ def tools_upgrade(operation_logger, apps=None, system=False):
logger.debug("Running apt command :\n{}".format(dist_upgrade))
def is_relevant(l):
return "Reading database ..." not in l.rstrip()
callbacks = (
lambda l: logger.info("+" + l.rstrip() + "\r"),
lambda l: logger.info("+ " + l.rstrip() + "\r") if is_relevant(l) else logger.debug(l.rstrip() + "\r"),
lambda l: logger.warning(l.rstrip()),
)
returncode = call_async_output(dist_upgrade, callbacks, shell=True)
if returncode != 0:
logger.warning('tools_upgrade_regular_packages_failed',
logger.warning(m18n.n('tools_upgrade_regular_packages_failed'),
packages_list=', '.join(noncritical_packages_upgradable))
operation_logger.error(m18n.n('packages_upgrade_failed'))
raise YunohostError(m18n.n('packages_upgrade_failed'))

View file

@ -32,10 +32,13 @@ import crypt
import random
import string
import subprocess
import copy
from moulinette import m18n
from yunohost.utils.error import YunohostError
from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import read_json, write_to_json, read_yaml, write_to_yaml
from yunohost.utils.error import YunohostError
from yunohost.service import service_status
from yunohost.log import is_unit_operation
@ -126,12 +129,18 @@ def user_create(operation_logger, username, firstname, lastname, mail, password,
ldap = _get_ldap_interface()
if username in user_list()["users"]:
raise YunohostError("user_already_exists", user=username)
# Validate uniqueness of username and mail in LDAP
ldap.validate_uniqueness({
'uid': username,
'mail': mail,
'cn': username
})
try:
ldap.validate_uniqueness({
'uid': username,
'mail': mail,
'cn': username
})
except Exception as e:
raise YunohostError('user_creation_failed', user=username, error=e)
# Validate uniqueness of username in system users
all_existing_usernames = {x.pw_name for x in pwd.getpwall()}
@ -188,49 +197,45 @@ def user_create(operation_logger, username, firstname, lastname, mail, password,
attr_dict['mail'] = [attr_dict['mail']] + aliases
# If exists, remove the redirection from the SSO
try:
with open('/etc/ssowat/conf.json.persistent') as json_conf:
ssowat_conf = json.loads(str(json_conf.read()))
except ValueError as e:
raise YunohostError('ssowat_persistent_conf_read_error', error=e.strerror)
except IOError:
if not os.path.exists('/etc/ssowat/conf.json.persistent'):
ssowat_conf = {}
else:
ssowat_conf = read_json('/etc/ssowat/conf.json.persistent')
if 'redirected_urls' in ssowat_conf and '/' in ssowat_conf['redirected_urls']:
del ssowat_conf['redirected_urls']['/']
try:
with open('/etc/ssowat/conf.json.persistent', 'w+') as f:
json.dump(ssowat_conf, f, sort_keys=True, indent=4)
except IOError as e:
raise YunohostError('ssowat_persistent_conf_write_error', error=e.strerror)
if ldap.add('uid=%s,ou=users' % username, attr_dict):
# Invalidate passwd to take user creation into account
subprocess.call(['nscd', '-i', 'passwd'])
write_to_json('/etc/ssowat/conf.json.persistent', ssowat_conf)
os.system('chmod 644 /etc/ssowat/conf.json.persistent')
try:
# Attempt to create user home folder
subprocess.check_call(
['su', '-', username, '-c', "''"])
except subprocess.CalledProcessError:
if not os.path.isdir('/home/{0}'.format(username)):
logger.warning(m18n.n('user_home_creation_failed'),
exc_info=1)
try:
ldap.add('uid=%s,ou=users' % username, attr_dict)
except Exception as e:
raise YunohostError('user_creation_failed', user=username, error=e)
# Create group for user and add to group 'all_users'
user_group_add(groupname=username, gid=uid, sync_perm=False)
user_group_update(groupname=username, add_user=username, force=True, sync_perm=False)
user_group_update(groupname='all_users', add_user=username, force=True, sync_perm=True)
# Invalidate passwd to take user creation into account
subprocess.call(['nscd', '-i', 'passwd'])
# TODO: Send a welcome mail to user
logger.success(m18n.n('user_created'))
try:
# Attempt to create user home folder
subprocess.check_call(
['su', '-', username, '-c', "''"])
except subprocess.CalledProcessError:
if not os.path.isdir('/home/{0}'.format(username)):
logger.warning(m18n.n('user_home_creation_failed'),
exc_info=1)
hook_callback('post_user_create',
args=[username, mail, password, firstname, lastname])
# Create group for user and add to group 'all_users'
user_group_create(groupname=username, gid=uid, primary_group=True, sync_perm=False)
user_group_update(groupname='all_users', add=username, force=True, sync_perm=True)
return {'fullname': fullname, 'username': username, 'mail': mail}
# TODO: Send a welcome mail to user
logger.success(m18n.n('user_created'))
raise YunohostError('user_creation_failed')
hook_callback('post_user_create',
args=[username, mail, password, firstname, lastname])
return {'fullname': fullname, 'username': username, 'mail': mail}
@is_unit_operation([('username', 'user')])
@ -245,32 +250,40 @@ def user_delete(operation_logger, username, purge=False):
"""
from yunohost.hook import hook_callback
from yunohost.utils.ldap import _get_ldap_interface
from yunohost.permission import permission_sync_to_user
if username not in user_list()["users"]:
raise YunohostError('user_unknown', user=username)
operation_logger.start()
user_group_update("all_users", remove=username, force=True, sync_perm=False)
for group, infos in user_group_list()["groups"].items():
if group == "all_users":
continue
# If the user is in this group (and it's not the primary group),
# remove the member from the group
if username != group and username in infos["members"]:
user_group_update(group, remove=username, sync_perm=False)
# Delete primary group if it exists (why wouldnt it exists ? because some
# epic bug happened somewhere else and only a partial removal was
# performed...)
if username in user_group_list()['groups'].keys():
user_group_delete(username, force=True, sync_perm=True)
ldap = _get_ldap_interface()
if ldap.remove('uid=%s,ou=users' % username):
# Invalidate passwd to take user deletion into account
subprocess.call(['nscd', '-i', 'passwd'])
try:
ldap.remove('uid=%s,ou=users' % username)
except Exception as e:
raise YunohostError('user_deletion_failed', user=username, error=e)
if purge:
subprocess.call(['rm', '-rf', '/home/{0}'.format(username)])
subprocess.call(['rm', '-rf', '/var/mail/{0}'.format(username)])
else:
raise YunohostError('user_deletion_failed')
# Invalidate passwd to take user deletion into account
subprocess.call(['nscd', '-i', 'passwd'])
user_group_delete(username, force=True, sync_perm=True)
group_list = ldap.search('ou=groups,dc=yunohost,dc=org',
'(&(objectclass=groupOfNamesYnh)(memberUid=%s))'
% username, ['cn'])
for group in group_list:
user_list = ldap.search('ou=groups,dc=yunohost,dc=org',
'cn=' + group['cn'][0],
['memberUid'])[0]
user_list['memberUid'].remove(username)
if not ldap.update('cn=%s,ou=groups' % group['cn'][0], user_list):
raise YunohostError('group_update_failed')
if purge:
subprocess.call(['rm', '-rf', '/home/{0}'.format(username)])
subprocess.call(['rm', '-rf', '/var/mail/{0}'.format(username)])
hook_callback('post_user_delete', args=[username, purge])
@ -338,7 +351,10 @@ def user_update(operation_logger, username, firstname=None, lastname=None, mail=
'webmaster@' + main_domain,
'postmaster@' + main_domain,
]
ldap.validate_uniqueness({'mail': mail})
try:
ldap.validate_uniqueness({'mail': mail})
except Exception as e:
raise YunohostError('user_update_failed', user=username, error=e)
if mail[mail.find('@') + 1:] not in domains:
raise YunohostError('mail_domain_unknown', domain=mail[mail.find('@') + 1:])
if mail in aliases:
@ -351,7 +367,10 @@ def user_update(operation_logger, username, firstname=None, lastname=None, mail=
if not isinstance(add_mailalias, list):
add_mailalias = [add_mailalias]
for mail in add_mailalias:
ldap.validate_uniqueness({'mail': mail})
try:
ldap.validate_uniqueness({'mail': mail})
except Exception as e:
raise YunohostError('user_update_failed', user=username, error=e)
if mail[mail.find('@') + 1:] not in domains:
raise YunohostError('mail_domain_unknown', domain=mail[mail.find('@') + 1:])
user['mail'].append(mail)
@ -391,12 +410,14 @@ def user_update(operation_logger, username, firstname=None, lastname=None, mail=
operation_logger.start()
if ldap.update('uid=%s,ou=users' % username, new_attr_dict):
logger.success(m18n.n('user_updated'))
app_ssowatconf()
return user_info(username)
else:
raise YunohostError('user_update_failed')
try:
ldap.update('uid=%s,ou=users' % username, new_attr_dict)
except Exception as e:
raise YunohostError('user_update_failed', user=username, error=e)
logger.success(m18n.n('user_updated'))
app_ssowatconf()
return user_info(username)
def user_info(username):
@ -453,7 +474,7 @@ def user_info(username):
if service_status("dovecot")["status"] != "running":
logger.warning(m18n.n('mailbox_used_space_dovecot_down'))
elif not user_permission_list(app="mail", permission="main", username=username)['permissions']:
elif username not in user_permission_list(full=True)["permissions"]["mail.main"]["corresponding_users"]:
logger.warning(m18n.n('mailbox_disabled', user=username))
else:
cmd = 'doveadm -f flow quota get -u %s' % user['uid'][0]
@ -480,81 +501,59 @@ def user_info(username):
'use': storage_use
}
if result:
return result_dict
else:
raise YunohostError('user_info_failed')
return result_dict
#
# Group subcategory
#
def user_group_list(fields=None):
def user_group_list(short=False, full=False, include_primary_groups=True):
"""
List users
Keyword argument:
filter -- LDAP filter used to search
offset -- Starting number for user fetching
limit -- Maximum number of user fetched
fields -- fields to fetch
short -- Only list the name of the groups without any additional info
full -- List all the info available for each groups
include_primary_groups -- Include groups corresponding to users (which should always only contains this user)
This option is set to false by default in the action map because we don't want to have
these displayed when the user runs `yunohost user group list`, but internally we do want
to list them when called from other functions
"""
from yunohost.utils.ldap import _get_ldap_interface
# Fetch relevant informations
from yunohost.utils.ldap import _get_ldap_interface, _ldap_path_extract
ldap = _get_ldap_interface()
group_attr = {
'cn': 'groupname',
'member': 'members',
'permission': 'permission'
}
attrs = ['cn']
groups_infos = ldap.search('ou=groups,dc=yunohost,dc=org',
'(objectclass=groupOfNamesYnh)',
["cn", "member", "permission"])
# Parse / organize information to be outputed
users = user_list()["users"]
groups = {}
for infos in groups_infos:
if fields:
keys = group_attr.keys()
for attr in fields:
if attr in keys:
attrs.append(attr)
else:
raise YunohostError('field_invalid', attr)
else:
attrs = ['cn', 'member']
name = infos["cn"][0]
result = ldap.search('ou=groups,dc=yunohost,dc=org',
'(objectclass=groupOfNamesYnh)',
attrs)
for group in result:
# The group "admins" should be hidden for the user
if group_attr['cn'] == "admins":
if not include_primary_groups and name in users:
continue
entry = {}
for attr, values in group.items():
if values:
if attr == "member":
entry[group_attr[attr]] = []
for v in values:
entry[group_attr[attr]].append(v.split("=")[1].split(",")[0])
elif attr == "permission":
entry[group_attr[attr]] = {}
for v in values:
permission = v.split("=")[1].split(",")[0].split(".")[1]
pType = v.split("=")[1].split(",")[0].split(".")[0]
if permission in entry[group_attr[attr]]:
entry[group_attr[attr]][permission].append(pType)
else:
entry[group_attr[attr]][permission] = [pType]
else:
entry[group_attr[attr]] = values[0]
groupname = entry[group_attr['cn']]
groups[groupname] = entry
groups[name] = {}
groups[name]["members"] = [_ldap_path_extract(p, "uid") for p in infos.get("member", [])]
if full:
groups[name]["permissions"] = [_ldap_path_extract(p, "cn") for p in infos.get("permission", [])]
if short:
groups = groups.keys()
return {'groups': groups}
@is_unit_operation([('groupname', 'user')])
def user_group_add(operation_logger, groupname, gid=None, sync_perm=True):
@is_unit_operation([('groupname', 'group')])
def user_group_create(operation_logger, groupname, gid=None, primary_group=False, sync_perm=True):
"""
Create group
@ -565,8 +564,6 @@ def user_group_add(operation_logger, groupname, gid=None, sync_perm=True):
from yunohost.permission import permission_sync_to_user
from yunohost.utils.ldap import _get_ldap_interface
operation_logger.start()
ldap = _get_ldap_interface()
# Validate uniqueness of groupname in LDAP
@ -574,12 +571,12 @@ def user_group_add(operation_logger, groupname, gid=None, sync_perm=True):
'cn': groupname
}, base_dn='ou=groups,dc=yunohost,dc=org')
if conflict:
raise YunohostError('group_name_already_exist', name=groupname)
raise YunohostError('group_already_exist', group=groupname)
# Validate uniqueness of groupname in system group
all_existing_groupnames = {x.gr_name for x in grp.getgrall()}
if groupname in all_existing_groupnames:
raise YunohostError('system_groupname_exists')
raise YunohostError('group_already_exist_on_system', group=groupname)
if not gid:
# Get random GID
@ -596,16 +593,30 @@ def user_group_add(operation_logger, groupname, gid=None, sync_perm=True):
'gidNumber': gid,
}
if ldap.add('cn=%s,ou=groups' % groupname, attr_dict):
# Here we handle the creation of a primary group
# We want to initialize this group to contain the corresponding user
# (then we won't be able to add/remove any user in this group)
if primary_group:
attr_dict["member"] = ["uid=" + groupname + ",ou=users,dc=yunohost,dc=org"]
operation_logger.start()
try:
ldap.add('cn=%s,ou=groups' % groupname, attr_dict)
except Exception as e:
raise YunohostError('group_creation_failed', group=groupname, error=e)
if sync_perm:
permission_sync_to_user()
if not primary_group:
logger.success(m18n.n('group_created', group=groupname))
if sync_perm:
permission_sync_to_user()
return {'name': groupname}
else:
logger.debug(m18n.n('group_created', group=groupname))
raise YunohostError('group_creation_failed', group=groupname)
return {'name': groupname}
@is_unit_operation([('groupname', 'user')])
@is_unit_operation([('groupname', 'group')])
def user_group_delete(operation_logger, groupname, force=False, sync_perm=True):
"""
Delete user
@ -617,102 +628,109 @@ def user_group_delete(operation_logger, groupname, force=False, sync_perm=True):
from yunohost.permission import permission_sync_to_user
from yunohost.utils.ldap import _get_ldap_interface
forbidden_groups = ["all_users", "admins"] + user_list(fields=['uid'])['users'].keys()
if not force and groupname in forbidden_groups:
raise YunohostError('group_deletion_not_allowed', group=groupname)
existing_groups = user_group_list()['groups'].keys()
if groupname not in existing_groups:
raise YunohostError('group_unknown', group=groupname)
# Refuse to delete primary groups of a user (e.g. group 'sam' related to user 'sam')
# without the force option...
#
# We also can't delete "all_users" because that's a special group...
existing_users = user_list()['users'].keys()
undeletable_groups = existing_users + ["all_users", "visitors"]
if groupname in undeletable_groups and not force:
raise YunohostError('group_cannot_be_deleted', group=groupname)
operation_logger.start()
ldap = _get_ldap_interface()
if not ldap.remove('cn=%s,ou=groups' % groupname):
raise YunohostError('group_deletion_failed', group=groupname)
try:
ldap.remove('cn=%s,ou=groups' % groupname)
except Exception as e:
raise YunohostError('group_deletion_failed', group=groupname, error=e)
logger.success(m18n.n('group_deleted', group=groupname))
if sync_perm:
permission_sync_to_user()
if groupname not in existing_users:
logger.success(m18n.n('group_deleted', group=groupname))
else:
logger.debug(m18n.n('group_deleted', group=groupname))
@is_unit_operation([('groupname', 'user')])
def user_group_update(operation_logger, groupname, add_user=None, remove_user=None, force=False, sync_perm=True):
@is_unit_operation([('groupname', 'group')])
def user_group_update(operation_logger, groupname, add=None, remove=None, force=False, sync_perm=True):
"""
Update user informations
Keyword argument:
groupname -- Groupname to update
add_user -- User to add in group
remove_user -- User to remove in group
add -- User(s) to add in group
remove -- User(s) to remove in group
"""
from yunohost.permission import permission_sync_to_user
from yunohost.utils.ldap import _get_ldap_interface
if (groupname == 'all_users' or groupname == 'admins') and not force:
raise YunohostError('edit_group_not_allowed', group=groupname)
existing_users = user_list()['users'].keys()
ldap = _get_ldap_interface()
# Refuse to edit a primary group of a user (e.g. group 'sam' related to user 'sam')
# Those kind of group should only ever contain the user (e.g. sam) and only this one.
# We also can't edit "all_users" without the force option because that's a special group...
if not force:
if groupname == "all_users":
raise YunohostError('group_cannot_edit_all_users')
elif groupname == "visitors":
raise YunohostError('group_cannot_edit_visitors')
elif groupname in existing_users:
raise YunohostError('group_cannot_edit_primary_group', group=groupname)
# Populate group informations
attrs_to_fetch = ['member']
result = ldap.search(base='ou=groups,dc=yunohost,dc=org',
filter='cn=' + groupname, attrs=attrs_to_fetch)
if not result:
raise YunohostError('group_unknown', group=groupname)
group = result[0]
# We extract the uid for each member of the group to keep a simple flat list of members
current_group = user_group_info(groupname)["members"]
new_group = copy.copy(current_group)
new_group_list = {'member': set(), 'memberUid': set()}
if 'member' in group:
new_group_list['member'] = set(group['member'])
else:
group['member'] = []
if add:
users_to_add = [add] if not isinstance(add, list) else add
existing_users = user_list(fields=['uid'])['users'].keys()
if add_user:
if not isinstance(add_user, list):
add_user = [add_user]
for user in add_user:
for user in users_to_add:
if user not in existing_users:
raise YunohostError('user_unknown', user=user)
for user in add_user:
userDN = "uid=" + user + ",ou=users,dc=yunohost,dc=org"
if userDN in group['member']:
logger.warning(m18n.n('user_already_in_group', user=user, group=groupname))
new_group_list['member'].add(userDN)
if remove_user:
if not isinstance(remove_user, list):
remove_user = [remove_user]
for user in remove_user:
if user == groupname:
raise YunohostError('remove_user_of_group_not_allowed', user=user, group=groupname)
for user in remove_user:
userDN = "uid=" + user + ",ou=users,dc=yunohost,dc=org"
if 'member' in group and userDN in group['member']:
new_group_list['member'].remove(userDN)
if user in current_group:
logger.warning(m18n.n('group_user_already_in_group', user=user, group=groupname))
else:
logger.warning(m18n.n('user_not_in_group', user=user, group=groupname))
operation_logger.related_to.append(('user', user))
# Sychronise memberUid with member (to keep the posix group structure)
# In posixgroup the main group of each user is only written in the gid number of the user
for member in new_group_list['member']:
member_Uid = member.split("=")[1].split(",")[0]
# Don't add main user in the group.
# Note that in the Unix system the main user of the group is linked by the gid in the user attribute.
# So the main user need to be not in the memberUid list of his own group.
if member_Uid != groupname:
new_group_list['memberUid'].add(member_Uid)
new_group += users_to_add
operation_logger.start()
if remove:
users_to_remove = [remove] if not isinstance(remove, list) else remove
if new_group_list['member'] != set(group['member']):
if not ldap.update('cn=%s,ou=groups' % groupname, new_group_list):
raise YunohostError('group_update_failed', group=groupname)
for user in users_to_remove:
if user not in current_group:
logger.warning(m18n.n('group_user_not_in_group', user=user, group=groupname))
else:
operation_logger.related_to.append(('user', user))
# Remove users_to_remove from new_group
# Kinda like a new_group -= users_to_remove
new_group = [u for u in new_group if u not in users_to_remove]
new_group_dns = ["uid=" + user + ",ou=users,dc=yunohost,dc=org" for user in new_group]
if set(new_group) != set(current_group):
operation_logger.start()
ldap = _get_ldap_interface()
try:
ldap.update('cn=%s,ou=groups' % groupname, {"member": set(new_group_dns), "memberUid": set(new_group)})
except Exception as e:
raise YunohostError('group_update_failed', group=groupname, error=e)
if groupname != "all_users":
logger.success(m18n.n('group_updated', group=groupname))
else:
logger.debug(m18n.n('group_updated', group=groupname))
logger.success(m18n.n('group_updated', group=groupname))
if sync_perm:
permission_sync_to_user()
return user_group_info(groupname)
@ -727,59 +745,46 @@ def user_group_info(groupname):
"""
from yunohost.utils.ldap import _get_ldap_interface
from yunohost.utils.ldap import _get_ldap_interface, _ldap_path_extract
ldap = _get_ldap_interface()
group_attrs = [
'cn', 'member', 'permission'
]
result = ldap.search('ou=groups,dc=yunohost,dc=org', "cn=" + groupname, group_attrs)
# Fetch info for this group
result = ldap.search('ou=groups,dc=yunohost,dc=org',
"cn=" + groupname,
["cn", "member", "permission"])
if not result:
raise YunohostError('group_unknown', group=groupname)
group = result[0]
infos = result[0]
result_dict = {
'groupname': group['cn'][0],
'member': None
# Format data
return {
'members': [_ldap_path_extract(p, "uid") for p in infos.get("member", [])],
'permissions': [_ldap_path_extract(p, "cn") for p in infos.get("permission", [])]
}
if 'member' in group:
result_dict['member'] = {m.split("=")[1].split(",")[0] for m in group['member']}
return result_dict
#
# Permission subcategory
#
def user_permission_list(app=None, permission=None, username=None, group=None, sync_perm=True):
def user_permission_list(short=False, full=False):
import yunohost.permission
return yunohost.permission.user_permission_list(app, permission, username, group)
return yunohost.permission.user_permission_list(short, full)
@is_unit_operation([('app', 'user')])
def user_permission_add(operation_logger, app, permission="main", username=None, group=None, sync_perm=True):
def user_permission_update(permission, add=None, remove=None, sync_perm=True):
import yunohost.permission
return yunohost.permission.user_permission_update(operation_logger, app, permission=permission,
add_username=username, add_group=group,
del_username=None, del_group=None,
return yunohost.permission.user_permission_update(permission,
add=add, remove=remove,
sync_perm=sync_perm)
@is_unit_operation([('app', 'user')])
def user_permission_remove(operation_logger, app, permission="main", username=None, group=None, sync_perm=True):
def user_permission_reset(permission, sync_perm=True):
import yunohost.permission
return yunohost.permission.user_permission_update(operation_logger, app, permission=permission,
add_username=None, add_group=None,
del_username=username, del_group=group,
sync_perm=sync_perm)
@is_unit_operation([('app', 'user')])
def user_permission_clear(operation_logger, app, permission=None, sync_perm=True):
import yunohost.permission
return yunohost.permission.user_permission_clear(operation_logger, app, permission,
return yunohost.permission.user_permission_reset(permission,
sync_perm=sync_perm)

View file

@ -33,6 +33,8 @@ class YunohostError(MoulinetteError):
"""
def __init__(self, key, raw_msg=False, *args, **kwargs):
self.key = key # Saving the key is useful for unit testing
self.kwargs = kwargs # Saving the key is useful for unit testing
if raw_msg:
msg = key
else:

View file

@ -40,6 +40,20 @@ def _get_ldap_interface():
return _ldap_interface
# We regularly want to extract stuff like 'bar' in ldap path like
# foo=bar,dn=users.example.org,ou=example.org,dc=org so this small helper allow
# to do this without relying of dozens of mysterious string.split()[0]
#
# e.g. using _ldap_path_extract(path, "foo") on the previous example will
# return bar
def _ldap_path_extract(path, info):
for element in path.split(","):
if element.startswith(info + "="):
return element[len(info + "="):]
# Add this to properly close / delete the ldap interface / authenticator
# when Python exits ...
# Otherwise there's a risk that some funky error appears at the very end

View file

@ -5,23 +5,37 @@ import glob
import json
import yaml
ignore = [ "service_description_",
"migration_description_",
"global_settings_setting_",
"password_too_simple_",
"password_listed",
"backup_method_",
"backup_applying_method_",
"confirm_app_install_",
"log_",
]
###############################################################################
# Find used keys in python code #
###############################################################################
# This regex matches « foo » in patterns like « m18n.n( "foo" »
p = re.compile(r'm18n\.n\(\s*[\"\']([a-zA-Z1-9_]+)[\"\']')
p1 = re.compile(r'm18n\.n\(\s*[\"\']([a-zA-Z0-9_]+)[\"\']')
p2 = re.compile(r'YunohostError\([\'\"]([a-zA-Z0-9_]+)[\'\"]')
python_files = glob.glob("/vagrant/yunohost/src/yunohost/*.py")
python_files.extend(glob.glob("/vagrant/yunohost/src/yunohost/utils/*.py"))
python_files.append("/vagrant/yunohost/bin/yunohost")
python_files = glob.glob("../src/yunohost/*.py")
python_files.extend(glob.glob("../src/yunohost/utils/*.py"))
python_files.extend(glob.glob("../src/yunohost/data_migrations/*.py"))
python_files.append("../bin/yunohost")
python_keys = set()
for python_file in python_files:
with open(python_file) as f:
keys_in_file = p.findall(f.read())
for key in keys_in_file:
python_keys.add(key)
content = open(python_file).read()
for match in p1.findall(content):
python_keys.add(match)
for match in p2.findall(content):
python_keys.add(match)
###############################################################################
# Find keys used in actionmap #
@ -42,19 +56,20 @@ for _, category in actionmap.items():
actionmap_keys.add(argument["extra"]["password"])
if "ask" in argument["extra"]:
actionmap_keys.add(argument["extra"]["ask"])
if "comment" in argument["extra"]:
actionmap_keys.add(argument["extra"]["comment"])
if "pattern" in argument["extra"]:
actionmap_keys.add(argument["extra"]["pattern"][1])
if "help" in argument["extra"]:
print argument["extra"]["help"]
# These keys are used but difficult to parse
actionmap_keys.add("admin_password")
###############################################################################
# Load en locale json keys #
###############################################################################
en_locale_file = "/vagrant/yunohost/locales/en.json"
en_locale_file = "../locales/en.json"
with open(en_locale_file) as f:
en_locale_json = json.loads(f.read())
@ -72,11 +87,15 @@ keys_defined_but_not_used = en_locale_keys.difference(used_keys)
if len(keys_used_but_not_defined) != 0:
print "> Error ! Those keys are used in some files but not defined :"
for key in sorted(keys_used_but_not_defined):
if any(key.startswith(i) for i in ignore):
continue
print " - %s" % key
if len(keys_defined_but_not_used) != 0:
print "> Warning ! Those keys are defined but seems unused :"
for key in sorted(keys_defined_but_not_used):
if any(key.startswith(i) for i in ignore):
continue
print " - %s" % key