mirror of
https://github.com/YunoHost/apps.git
synced 2024-09-03 20:06:07 +02:00
appstore: initialize i18n stuff
This commit is contained in:
parent
fdad58a45d
commit
55e0a098ef
13 changed files with 473 additions and 99 deletions
1
store/.gitignore
vendored
1
store/.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
config.toml
|
||||
.stars
|
||||
messages.pot
|
||||
|
|
|
@ -29,3 +29,21 @@ And then start the dev server:
|
|||
source venv/bin/activate
|
||||
FLASK_APP=app.py FLASK_ENV=development flask run
|
||||
```
|
||||
|
||||
## Translation
|
||||
|
||||
It's based on Flask-Babel : https://python-babel.github.io/
|
||||
|
||||
```
|
||||
source venv/bin/activate
|
||||
pybabel extract --ignore-dirs venv -F babel.cfg -o messages.pot .
|
||||
|
||||
# If working on a new locale : initialize it (in this example: fr)
|
||||
pybabel init -i messages.pot -d translations -l fr
|
||||
# Otherwise, update the existing .po:
|
||||
pybabel update -i messages.pot -d translations
|
||||
|
||||
# ... translate stuff in translations/<lang>/LC_MESSAGES/messages.po
|
||||
# then compile:
|
||||
pybabel compile -d translations
|
||||
```
|
||||
|
|
71
store/app.py
71
store/app.py
|
@ -11,6 +11,8 @@ import json
|
|||
import sys
|
||||
from slugify import slugify
|
||||
from flask import Flask, send_from_directory, render_template, session, redirect, request
|
||||
from flask_babel import Babel
|
||||
from flask_babel import gettext as _
|
||||
from github import Github, InputGitAuthor
|
||||
from .utils import get_catalog, get_wishlist, get_stars, get_app_md_and_screenshots
|
||||
|
||||
|
@ -46,6 +48,26 @@ if config.get("DEBUG"):
|
|||
# This is the secret key used for session signing
|
||||
app.secret_key = config["COOKIE_SECRET"]
|
||||
|
||||
AVAILABLE_LANGUAGES = ["en"] + os.listdir("translations")
|
||||
|
||||
def get_locale():
|
||||
# try to guess the language from the user accept
|
||||
# header the browser transmits. We support de/fr/en in this
|
||||
# example. The best match wins.
|
||||
return request.accept_languages.best_match(AVAILABLE_LANGUAGES)
|
||||
babel = Babel(app, locale_selector=get_locale)
|
||||
|
||||
@app.template_filter('localize')
|
||||
def localize(d):
|
||||
if not isinstance(d, dict):
|
||||
return d
|
||||
else:
|
||||
locale = get_locale()
|
||||
if locale in d:
|
||||
return d[locale]
|
||||
else:
|
||||
return d["en"]
|
||||
|
||||
###############################################################################
|
||||
|
||||
@app.route('/favicon.ico')
|
||||
|
@ -55,13 +77,14 @@ def favicon():
|
|||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return render_template("index.html", user=session.get('user', {}), catalog=get_catalog())
|
||||
return render_template("index.html", locale=get_locale(), user=session.get('user', {}), catalog=get_catalog())
|
||||
|
||||
|
||||
@app.route('/catalog')
|
||||
def browse_catalog():
|
||||
return render_template(
|
||||
"catalog.html",
|
||||
locale=get_locale(),
|
||||
init_sort=request.args.get("sort"),
|
||||
init_search=request.args.get("search"),
|
||||
init_category=request.args.get("category"),
|
||||
|
@ -69,7 +92,7 @@ def browse_catalog():
|
|||
user=session.get('user', {}),
|
||||
catalog=get_catalog(),
|
||||
timestamp_now=int(time.time()),
|
||||
stars=get_stars()
|
||||
stars=get_stars(),
|
||||
)
|
||||
|
||||
|
||||
|
@ -82,16 +105,16 @@ def app_info(app_id):
|
|||
|
||||
get_app_md_and_screenshots(app_folder, infos)
|
||||
|
||||
return render_template("app.html", user=session.get('user', {}), app_id=app_id, infos=infos, catalog=get_catalog(), stars=get_stars())
|
||||
return render_template("app.html", locale=get_locale(), user=session.get('user', {}), app_id=app_id, infos=infos, catalog=get_catalog(), stars=get_stars())
|
||||
|
||||
|
||||
@app.route('/app/<app_id>/<action>')
|
||||
def star_app(app_id, action):
|
||||
assert action in ["star", "unstar"]
|
||||
if app_id not in get_catalog()["apps"] and app_id not in get_wishlist():
|
||||
return f"App {app_id} not found", 404
|
||||
return _("App %(app_id) not found", app_id=app_id), 404
|
||||
if not session.get('user', {}):
|
||||
return f"You must be logged in to be able to star an app", 401
|
||||
return _("You must be logged in to be able to star an app"), 401
|
||||
|
||||
app_star_folder = os.path.join(".stars", app_id)
|
||||
app_star_for_this_user = os.path.join(".stars", app_id, session.get('user', {})["id"])
|
||||
|
@ -114,7 +137,7 @@ def star_app(app_id, action):
|
|||
|
||||
@app.route('/wishlist')
|
||||
def browse_wishlist():
|
||||
return render_template("wishlist.html", user=session.get('user', {}), wishlist=get_wishlist(), stars=get_stars())
|
||||
return render_template("wishlist.html", locale=get_locale(), user=session.get('user', {}), wishlist=get_wishlist(), stars=get_stars())
|
||||
|
||||
|
||||
@app.route('/wishlist/add', methods=['GET', 'POST'])
|
||||
|
@ -123,8 +146,8 @@ def add_to_wishlist():
|
|||
|
||||
user = session.get('user', {})
|
||||
if not user:
|
||||
errormsg = "You must be logged in to submit an app to the wishlist"
|
||||
return render_template("wishlist_add.html", user=session.get('user', {}), successmsg=None, errormsg=errormsg)
|
||||
errormsg = _("You must be logged in to submit an app to the wishlist")
|
||||
return render_template("wishlist_add.html", locale=get_locale(), user=session.get('user', {}), successmsg=None, errormsg=errormsg)
|
||||
|
||||
name = request.form['name'].strip().replace("\n", "")
|
||||
description = request.form['description'].strip().replace("\n", "")
|
||||
|
@ -132,19 +155,19 @@ def add_to_wishlist():
|
|||
website = request.form['website'].strip().replace("\n", "")
|
||||
|
||||
checks = [
|
||||
(len(name) >= 3, "App name should be at least 3 characters"),
|
||||
(len(name) <= 30, "App name should be less than 30 characters"),
|
||||
(len(description) >= 5, "App name should be at least 5 characters"),
|
||||
(len(description) <= 100, "App name should be less than 100 characters"),
|
||||
(len(upstream) >= 10, "Upstream code repo URL should be at least 10 characters"),
|
||||
(len(upstream) <= 150, "Upstream code repo URL should be less than 150 characters"),
|
||||
(len(website) <= 150, "Website URL should be less than 150 characters"),
|
||||
(re.match(r"^[\w\.\-\(\)\ ]+$", name), "App name contains special characters"),
|
||||
(len(name) >= 3, _("App name should be at least 3 characters")),
|
||||
(len(name) <= 30, _("App name should be less than 30 characters")),
|
||||
(len(description) >= 5, _("App description should be at least 5 characters")),
|
||||
(len(description) <= 100, _("App description should be less than 100 characters")),
|
||||
(len(upstream) >= 10, _("Upstream code repo URL should be at least 10 characters")),
|
||||
(len(upstream) <= 150, _("Upstream code repo URL should be less than 150 characters")),
|
||||
(len(website) <= 150, _("Website URL should be less than 150 characters")),
|
||||
(re.match(r"^[\w\.\-\(\)\ ]+$", name), _("App name contains special characters")),
|
||||
]
|
||||
|
||||
for check, errormsg in checks:
|
||||
if not check:
|
||||
return render_template("wishlist_add.html", user=session.get('user', {}), successmsg=None, errormsg=errormsg)
|
||||
return render_template("wishlist_add.html", locale=get_locale(), user=session.get('user', {}), successmsg=None, errormsg=errormsg)
|
||||
|
||||
slug = slugify(name)
|
||||
github = Github(config["GITHUB_TOKEN"])
|
||||
|
@ -156,7 +179,7 @@ def add_to_wishlist():
|
|||
new_wishlist = toml.loads(current_wishlist_rawtoml)
|
||||
|
||||
if slug in new_wishlist:
|
||||
return render_template("wishlist_add.html", user=session.get('user', {}), successmsg=None, errormsg=f"An entry with the name {slug} already exists in the wishlist")
|
||||
return render_template("wishlist_add.html", locale=get_locale(), user=session.get('user', {}), successmsg=None, errormsg=_("An entry with the name %(slug) already exists in the wishlist", slug=slug))
|
||||
|
||||
new_wishlist[slug] = {
|
||||
"name": name,
|
||||
|
@ -175,8 +198,8 @@ def add_to_wishlist():
|
|||
except exception as e:
|
||||
print("... Failed to create branch ?")
|
||||
print(e)
|
||||
errormsg = "Failed to create the pull request to add the app to the wishlist ... please report the issue to the yunohost team"
|
||||
return render_template("wishlist_add.html", user=session.get('user', {}), successmsg=None, errormsg=errormsg)
|
||||
errormsg = _("Failed to create the pull request to add the app to the wishlist ... please report the issue to the yunohost team")
|
||||
return render_template("wishlist_add.html", locale=get_locale(), user=session.get('user', {}), successmsg=None, errormsg=errormsg)
|
||||
|
||||
message = f"Add {name} to wishlist"
|
||||
repo.update_file(
|
||||
|
@ -206,10 +229,12 @@ Proposed by **{session['user']['username']}**
|
|||
title=message, body=body, head=new_branch, base="app-store" # FIXME app-store -> repo.default_branch
|
||||
)
|
||||
|
||||
successmsg = f"Your proposed app has succesfully been submitted. It must now be validated by the YunoHost team. You can track progress here: https://github.com/YunoHost/apps/pull/{pr.number}"
|
||||
return render_template("wishlist_add.html", user=session.get('user', {}), successmsg=successmsg)
|
||||
url = f"https://github.com/YunoHost/apps/pull/{pr.number}"
|
||||
|
||||
successmsg = _("Your proposed app has succesfully been submitted. It must now be validated by the YunoHost team. You can track progress here: %(url)s", url=url)
|
||||
return render_template("wishlist_add.html", locale=get_locale(), user=session.get('user', {}), successmsg=successmsg)
|
||||
else:
|
||||
return render_template("wishlist_add.html", user=session.get('user', {}), successmsg=None, errormsg=None)
|
||||
return render_template("wishlist_add.html", locale=get_locale(), user=session.get('user', {}), successmsg=None, errormsg=None)
|
||||
|
||||
|
||||
###############################################################################
|
||||
|
|
2
store/babel.cfg
Normal file
2
store/babel.cfg
Normal file
|
@ -0,0 +1,2 @@
|
|||
[python: **.py]
|
||||
[jinja2: **/templates/**.html]
|
|
@ -5,3 +5,5 @@ toml
|
|||
pycmarkgfm
|
||||
gunicorn
|
||||
emoji
|
||||
Babel
|
||||
Flask-Babel
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
{% set locale = 'en' %}
|
||||
{% extends "base.html" %}
|
||||
{% block main %}
|
||||
<div class="max-w-screen-md mx-auto pt-5">
|
||||
|
@ -15,7 +14,7 @@
|
|||
<h2 class="pl-2 pt-3 text-3xl font-bold text-gray-900">{{ infos["manifest"]["name"] }}</h2>
|
||||
{% if infos['category'] %}
|
||||
<span class="ml-2 mb-1 rounded-full px-2.5 py-0.5 text-[10px] border text-{{ catalog['categories'][infos['category']]['color'] }}-500 border-{{ catalog['categories'][infos['category']]['color'] }}-400 ">
|
||||
{{ catalog['categories'][infos['category']]['title'][locale].lower() }}
|
||||
{{ catalog['categories'][infos['category']]['title']|localize|lower }}
|
||||
</span>
|
||||
{% endif %}
|
||||
<div class="grow"></div>
|
||||
|
@ -65,7 +64,7 @@
|
|||
href="{{ infos["manifest"]["upstream"]["demo"] }}"
|
||||
>
|
||||
<i class="fa fa-external-link fa-fw" aria-hidden="true"></i>
|
||||
Try the demo
|
||||
{{ _("Try the demo") }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
@ -77,9 +76,9 @@
|
|||
|
||||
</span>
|
||||
|
||||
<p class="text-sm text-slate-500">Current version: {{ infos["manifest"]["version"] }}</p>
|
||||
<p class="text-sm text-slate-500">{{ _("Current version: %(version)s", version=infos["manifest"]["version"]) }}</p>
|
||||
{% if infos["potential_alternative_to"] %}
|
||||
<p class="text-sm text-slate-500">Potential alternative to: {{ infos["potential_alternative_to"]|join(', ') }}</p>
|
||||
<p class="text-sm text-slate-500">{{ _("Potential alternative to: %(alternatives)s", alternatives=infos["potential_alternative_to"]|join(', ')) }}</p>
|
||||
{% endif %}
|
||||
|
||||
<div class="from-markdown">{{ infos["full_description_html"]|safe }}</div>
|
||||
|
@ -90,44 +89,45 @@
|
|||
|
||||
{% if infos["manifest"]["integration"]["architectures"] != "all" %}
|
||||
<div class="my-3 rounded-md bg-orange-200 text-orange-800 px-5 py-2">
|
||||
<i class="fa fa-exclamation-triangle fa-fw"></i> This app is only compatible with these specific architectures : {{ infos["manifest"]["integration"]["architectures"]|join(', ') }}
|
||||
<i class="fa fa-exclamation-triangle fa-fw"></i> {{ _("This app is only compatible with these specific architectures: %(archs)s", archs=infos["manifest"]["integration"]["architectures"]|join(', ')) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if infos["manifest"]["integration"]["ram"]["build_binary"] >= 500 * 1024 * 1024 %}
|
||||
<div class="my-3 rounded-md bg-orange-200 text-orange-800 px-5 py-2">
|
||||
<i class="fa fa-exclamation-triangle fa-fw"></i> This app requires an unusual amount of RAM to build : {{ infos["manifest"]["integration"]["ram"]["build"] }}
|
||||
<i class="fa fa-exclamation-triangle fa-fw"></i> {{ _("This app requires an unusual amount of RAM to install: %(ram)s", ram=infos["manifest"]["integration"]["ram"]["build"]) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if infos["pre_install_html"] %}
|
||||
<div class="my-3 rounded-md bg-blue-200 text-blue-800 px-5 py-2">
|
||||
<h3 class="inline-block text-xl mb-2 font-semibold">Important infos before installing</h3>
|
||||
<h3 class="inline-block text-xl mb-2 font-semibold">{{ _("Important infos before installing") }}</h3>
|
||||
<div class="from-markdown">{{ infos["pre_install_html"] | safe }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if infos["antifeatures"] %}
|
||||
<h3 class="inline-block text-xl mb-2 font-semibold">Anti-features</h3> <p class="inline-block text-sm">(This app has features you may not like)</p>
|
||||
<h3 class="inline-block text-xl mb-2 font-semibold">{{ _("Anti-features") }}</h3>
|
||||
<p class="inline-block text-sm">{{ _("(This app has features you may not like)") }}</p>
|
||||
<div class="my-3 rounded-md bg-red-200 text-red-800 px-5 py-2">
|
||||
<ul>
|
||||
{% for antifeature in infos["antifeatures"] %}
|
||||
<li class="mb-1"><i class="fa fa-{{ catalog['antifeatures'][antifeature]['icon'] }} fa-fw" aria-hidden="true"></i> {{ catalog['antifeatures'][antifeature]['description'][locale] }}</li>
|
||||
<li class="mb-1"><i class="fa fa-{{ catalog['antifeatures'][antifeature]['icon'] }} fa-fw" aria-hidden="true"></i> {{ catalog['antifeatures'][antifeature]['description']|localize }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<h3 class="text-xl mb-2 font-semibold">Useful links</h3>
|
||||
<h3 class="text-xl mb-2 font-semibold">{{ _("Useful links") }}</h3>
|
||||
<div>
|
||||
{% set upstream = infos["manifest"]["upstream"] %}
|
||||
<a class="block btn btn-link my-1" href="https://spdx.org/licenses/{{upstream.license}}"><i class="fa fa-institution fa-fw" aria-hidden="true"></i> License : {{ upstream.license }}</a>
|
||||
{% if upstream.website %}<a class="block btn btn-link my-1" href="{{ upstream.website }}"><i class="fa fa-globe fa-fw" aria-hidden="true"></i> Official website</a>{% endif %}
|
||||
{% if upstream.admindoc %}<a class="block btn btn-link my-1" href="{{ upstream.admindoc }}"><i class="fa fa-book fa-fw" aria-hidden="true"></i> Official admin documentation</a>{% endif %}
|
||||
{% if upstream.userdoc %}<a class="block btn btn-link my-1" href="{{ upstream.userdoc }}"><i class="fa fa-book fa-fw" aria-hidden="true"></i> Official user documentation</a>{% endif %}
|
||||
{% if upstream.code %}<a class="block btn btn-link my-1" href="{{ upstream.code }}"><i class="fa fa-code fa-fw" aria-hidden="true"></i> Official code repository</a>{% endif %}
|
||||
<a class="block btn btn-link my-1" href="{{ infos["git"]["url"] }}"><i class="fa fa-code fa-fw" aria-hidden="true"></i> YunoHost package repository</a>
|
||||
<a class="block btn btn-link my-1" href="https://spdx.org/licenses/{{upstream.license}}"><i class="fa fa-institution fa-fw" aria-hidden="true"></i> {{ _("License: %(license)s", license=upstream.license) }}</a>
|
||||
{% if upstream.website %}<a class="block btn btn-link my-1" href="{{ upstream.website }}"><i class="fa fa-globe fa-fw" aria-hidden="true"></i> {{ _(" Official website") }}</a>{% endif %}
|
||||
{% if upstream.admindoc %}<a class="block btn btn-link my-1" href="{{ upstream.admindoc }}"><i class="fa fa-book fa-fw" aria-hidden="true"></i> {{ _("Official admin documentation") }}</a>{% endif %}
|
||||
{% if upstream.userdoc %}<a class="block btn btn-link my-1" href="{{ upstream.userdoc }}"><i class="fa fa-book fa-fw" aria-hidden="true"></i> {{ _("Official user documentation") }}</a>{% endif %}
|
||||
{% if upstream.code %}<a class="block btn btn-link my-1" href="{{ upstream.code }}"><i class="fa fa-code fa-fw" aria-hidden="true"></i> {{ _("Official code repository") }}</a>{% endif %}
|
||||
<a class="block btn btn-link my-1" href="{{ infos["git"]["url"] }}"><i class="fa fa-code fa-fw" aria-hidden="true"></i> {{ _("YunoHost package repository") }}</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="{{ locale }}">
|
||||
|
||||
<head>
|
||||
<title>YunoHost app store</title>
|
||||
<title>{{ _("YunoHost app store") }}</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="{{ url_for('static', filename='tailwindcss.js') }}"></script>
|
||||
|
@ -53,7 +53,7 @@
|
|||
class="flex h-16 items-center gap-8 px-4 sm:px-6 lg:px-8"
|
||||
>
|
||||
<a class="block text-teal-600" href="/">
|
||||
<span class="sr-only">Home</span>
|
||||
<span class="sr-only">{{ _("Home") }}</span>
|
||||
<img src="{{ url_for('static', filename='ynh_logo_roundcorner.png') }}" style="height: 3em;" />
|
||||
</a>
|
||||
|
||||
|
@ -62,13 +62,13 @@
|
|||
<ul class="flex items-center gap-6 text-sm">
|
||||
<li>
|
||||
<a class="text-gray-800 font-bold transition hover:text-gray-500/75" href="{{ url_for('browse_catalog') }}">
|
||||
Catalog
|
||||
{{ _("Catalog") }}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a class="text-gray-800 font-bold transition hover:text-gray-500/75" href="{{ url_for('browse_wishlist') }}">
|
||||
Wishlist
|
||||
{{ _("Wishlist") }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -81,21 +81,21 @@
|
|||
href="https://yunohost.org/docs/"
|
||||
>
|
||||
<i class="fa fa-external-link fa-fw" aria-hidden="true"></i>
|
||||
YunoHost documentation
|
||||
{{ _("YunoHost documentation") }}
|
||||
</a>
|
||||
{% if not user %}
|
||||
<a
|
||||
class="btn btn-primary hidden md:inline-block"
|
||||
href="{{ url_for('login_using_discourse') }}"
|
||||
>
|
||||
Login using YunoHost's forum
|
||||
{{ _("Login using YunoHost's forum") }}
|
||||
</a>
|
||||
{% else %}
|
||||
<button
|
||||
type="button"
|
||||
class="group flex shrink-0 items-center rounded-lg transition"
|
||||
>
|
||||
<span class="sr-only">Menu</span>
|
||||
<span class="sr-only">{{ _("Menu") }}</span>
|
||||
<img
|
||||
alt="Man"
|
||||
src="{{ user['avatar_url'] }}"
|
||||
|
@ -120,7 +120,7 @@
|
|||
<button
|
||||
class="block rounded bg-gray-100 p-2.5 text-gray-600 transition hover:text-gray-600/75 md:hidden"
|
||||
>
|
||||
<span class="sr-only">Toggle menu</span>
|
||||
<span class="sr-only">{{ _("Toggle menu") }}</span>
|
||||
<i class="fa fa-bars h-5 w-5" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
{% set locale = 'en' %}
|
||||
|
||||
{% macro appCard(app, infos, timestamp_now, catalog) -%}
|
||||
|
||||
{% set this_app_stars = stars.get(app, {})|length %}
|
||||
|
@ -53,14 +51,14 @@
|
|||
</span>
|
||||
</span>
|
||||
<p class="max-w-[40ch] text-xs text-gray-500">
|
||||
{{ infos['manifest']['description']['en'] }}
|
||||
{{ infos['manifest']['description']|localize }}
|
||||
</p>
|
||||
<div class="hidden">
|
||||
{{ infos["potential_alternative_to"]|join(', ') }}
|
||||
</div>
|
||||
{% if infos['category'] %}
|
||||
<span class="rounded-full px-2.5 py-0.5 text-[10px] border text-{{ catalog['categories'][infos['category']]['color'] }}-500 border-{{ catalog['categories'][infos['category']]['color'] }}-400 ">
|
||||
{{ catalog['categories'][infos['category']]['title'][locale].lower() }}
|
||||
{{ catalog['categories'][infos['category']]['title']|localize|lower }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
@ -73,18 +71,18 @@
|
|||
{% block main %}
|
||||
<div class="mt-5 text-center">
|
||||
<h2 class="text-2xl font-bold text-gray-900">
|
||||
Application Catalog
|
||||
{{ _("Application Catalog") }}
|
||||
</h2>
|
||||
</div>
|
||||
<div class="max-w-screen-md mx-auto mt-3 mb-3">
|
||||
<div class="flex flex-row">
|
||||
<div class="px-2 inline-block relative basis-2/3 text-gray-700">
|
||||
<label for="search" class="sr-only"> Search </label>
|
||||
<label for="search" class="sr-only"> {{ _("Search") }} </label>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
id="search"
|
||||
placeholder="Search for..."
|
||||
placeholder="{{ _('Search for...') }}"
|
||||
{% if init_search %}value="{{ init_search }}"{% endif %}
|
||||
class="w-full rounded-md border-gray-200 shadow-sm sm:text-sm py-2 pe-10"
|
||||
/>
|
||||
|
@ -100,10 +98,10 @@
|
|||
id="selectcategory"
|
||||
class="w-full rounded-md border-gray-200 shadow-sm sm:test-sm px-2 py-1.5"
|
||||
>
|
||||
<option value="">All apps</option>
|
||||
<option value="">{{ _("All apps") }}</option>
|
||||
{% for id, category in catalog['categories'].items() %}
|
||||
{{ category['title'][locale] }}
|
||||
<option {% if id == init_category %}selected{% endif %} value="{{ id }}" {{ id == init_category }} >{{ category['title'][locale] }}</option>
|
||||
{{ category['title']|localize }}
|
||||
<option {% if id == init_category %}selected{% endif %} value="{{ id }}" {{ id == init_category }} >{{ category['title']|localize }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
@ -111,15 +109,15 @@
|
|||
|
||||
<div class="flex flex-row justify-center items-center pt-2 text-center text-sm">
|
||||
<div class="inline-block px-2">
|
||||
Sort by
|
||||
{{ _("Sort by") }}
|
||||
<select
|
||||
name="selectsort"
|
||||
id="selectsort"
|
||||
class="inline-block rounded-md border-gray-200 text-sm ml-1 pl-1 pr-7 h-8 py-0"
|
||||
>
|
||||
<option {% if not init_sort %}selected{% endif %} value="">Alphabetical</option>
|
||||
<option {% if init_sort == "newest" %}selected{% endif %} value="newest">Newest</option>
|
||||
<option {% if init_sort == "popularity" %}selected{% endif %} value="popularity">Popularity</option>
|
||||
<option {% if not init_sort %}selected{% endif %} value="">{{ _("Alphabetical") }}</option>
|
||||
<option {% if init_sort == "newest" %}selected{% endif %} value="newest">{{ _("Newest") }}</option>
|
||||
<option {% if init_sort == "popularity" %}selected{% endif %} value="popularity">{{ _("Popularity") }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="inline-block flex items-center px-2">
|
||||
|
@ -132,7 +130,7 @@
|
|||
<span class="absolute inset-y-0 start-0 m-1 h-2 w-2 rounded-full bg-white transition-all peer-checked:start-3">
|
||||
</span>
|
||||
</label>
|
||||
Show only apps you starred
|
||||
{{ _("Show only apps you starred") }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -148,21 +146,21 @@
|
|||
|
||||
<div id="noResultFound" class="text-center pt-5 hidden">
|
||||
<p class="text-lg font-bold text-gray-900 mb-5">
|
||||
No results found
|
||||
{{ _("No results found.") }}
|
||||
</p>
|
||||
<p class="text-md text-gray-900">
|
||||
Not finding what you are looking for ?<br/>
|
||||
Checkout the wishlist !
|
||||
{{ _("Not finding what you are looking for?") }}<br/>
|
||||
{{ _("Checkout the wishlist!") }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div id="lowQualityAppTitle" class="text-center pt-10">
|
||||
<h2 class="text-lg font-bold text-gray-900">
|
||||
Applications currently broken or low-quality
|
||||
{{ _("Applications currently flagged as broken or low-quality") }}
|
||||
</h2>
|
||||
<p class="text-sm">
|
||||
These are apps which failed our automatic tests.<br/>
|
||||
This is usually a temporary situation which requires packagers to fix something in the app.
|
||||
{{ _("These are apps which failed our automatic tests.") }}<br/>
|
||||
{{ _("This is usually a temporary situation which requires packagers to fix something in the app.") }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
{% extends "base.html" %}
|
||||
{% block main %}
|
||||
{% set locale = 'en' %}
|
||||
|
||||
<div class="mx-auto w-full text-center p-8">
|
||||
<img src="{{ url_for('static', filename='ynh_logo_black.svg') }}" class="w-32 mx-auto" />
|
||||
<h2 class="text-2xl font-bold text-gray-900">
|
||||
Application Store
|
||||
{{ _("Application Store") }}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
|
@ -16,7 +15,7 @@
|
|||
class="h-full relative block overflow-hidden hover:bg-gray-200 pt-12"
|
||||
>
|
||||
<h3 class="text-md font-bold text-gray-900">
|
||||
Browse all applications
|
||||
{{ _("Browse all applications") }}
|
||||
</h3>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -28,10 +27,10 @@
|
|||
>
|
||||
<h3 class="text-md font-bold text-gray-900">
|
||||
<i class="fa fa-{{ category['icon'] }}" aria-hidden="true"></i>
|
||||
{{ category['title'][locale] }}
|
||||
{{ category['title']|localize }}
|
||||
</h3>
|
||||
<p class="mx-auto max-w-[40ch] text-xs text-gray-500">
|
||||
{{ category['description'][locale] }}
|
||||
{{ category['description']|localize }}
|
||||
</p>
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
@ -2,19 +2,19 @@
|
|||
{% block main %}
|
||||
<div class="mt-5 text-center">
|
||||
<h2 class="text-2xl font-bold text-gray-900">
|
||||
Application Wishlist
|
||||
{{ _("Application Wishlist") }}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div class="max-w-screen-md mx-auto mt-3 mb-3">
|
||||
<div class="flex flex-row">
|
||||
<div class="px-2 inline-block relative basis-2/3 text-gray-700">
|
||||
<label for="search" class="sr-only"> Search </label>
|
||||
<label for="search" class="sr-only"> {{ _("Search") }} </label>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
id="search"
|
||||
placeholder="Search for..."
|
||||
placeholder="{{ _('Search for...') }}"
|
||||
class="w-full rounded-md border-gray-200 shadow-sm sm:text-sm py-2 pe-10"
|
||||
/>
|
||||
|
||||
|
@ -23,33 +23,28 @@
|
|||
</span>
|
||||
</div>
|
||||
|
||||
<a
|
||||
|
||||
class="btn btn-primary-outline"
|
||||
href="{{ url_for('add_to_wishlist') }}"
|
||||
>
|
||||
<a class="btn btn-primary-outline" href="{{ url_for('add_to_wishlist') }}">
|
||||
<i class="fa fa-plus fa-fw" aria-hidden="true"></i>
|
||||
Add an app to the wishlist
|
||||
{{ _("Suggest an app") }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="overflow-x-auto max-w-screen-lg mx-auto pt-5">
|
||||
<table class="min-w-full divide-y-2 divide-gray-200 bg-white text-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="whitespace-nowrap px-4 py-2 font-medium text-gray-900">
|
||||
Name
|
||||
{{ _("Name") }}
|
||||
</th>
|
||||
<th class="whitespace-nowrap px-4 py-2 font-medium text-gray-900">
|
||||
Description
|
||||
{{ _("Description") }}
|
||||
</th>
|
||||
<th class="py-2"></th>
|
||||
<th class="py-2"></th>
|
||||
<th class="whitespace-nowrap px-4 py-2 font-medium text-gray-900 max-w-[5em]">Popularity</th>
|
||||
<th class="whitespace-nowrap px-4 py-2 font-medium text-gray-900 max-w-[5em]">{{ _("Popularity") }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
{% block main %}
|
||||
<div class="mt-5 text-center">
|
||||
<h2 class="text-2xl font-bold text-gray-900">
|
||||
Add an application to the wishlist
|
||||
{{ _("Suggest an application to be added to YunoHost's catalog") }}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
|||
<div role="alert" class="rounded-md border-s-4 border-orange-500 bg-orange-50 p-4 mb-5">
|
||||
<p class="mt-2 text-sm text-orange-700 font-bold">
|
||||
<i class="fa fa-exclamation-triangle fa-fw" aria-hidden="true"></i>
|
||||
You must first login to be allowed to submit an app to the wishlist
|
||||
{{ _("You must first login to be allowed to submit an app to the wishlist") }}
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
@ -31,10 +31,10 @@
|
|||
<div role="alert" class="rounded-md border-s-4 border-sky-500 bg-sky-50 p-4">
|
||||
<p class="mt-2 text-sm text-sky-700 font-bold">
|
||||
<i class="fa fa-info-circle fa-fw" aria-hidden="true"></i>
|
||||
Please check the license of the app your are proposing
|
||||
{{ _("Please check the license of the app your are proposing") }}
|
||||
</p>
|
||||
<p class="mt-2 text-sm text-sky-700">
|
||||
The YunoHost project will only package free/open-source software (with possible case-by-case exceptions for apps which are not-totally-free)
|
||||
{{ _("The YunoHost project will only package free/open-source software (with possible case-by-case exceptions for apps which are not-totally-free)") }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
@ -50,26 +50,26 @@
|
|||
|
||||
<form method="POST" action="{{ url_for('add_to_wishlist') }}" class="mt-8 mb-8" >
|
||||
|
||||
<label for="name" class="mt-5 block font-bold text-gray-700">Name</label>
|
||||
<label for="name" class="mt-5 block font-bold text-gray-700">{{ _("Name") }}</label>
|
||||
<input name="name" type="text" class="w-full mt-1 rounded-md border-gray-200 text-gray-700 shadow-sm" maxlength="30" required onkeyup="this.value = this.value.replace(/[^a-zA-Z0-9.-\\(\\)\\ ]/, '')" />
|
||||
|
||||
<label for="description" class="mt-5 block font-bold text-gray-700">Description</label>
|
||||
<label for="description" class="mt-5 block font-bold text-gray-700">{{ _("Description") }}</label>
|
||||
<textarea name="description" type="text" class="w-full mt-1 rounded-md border-gray-200 text-gray-700 shadow-sm" required rows='3' maxlength='100'></textarea>
|
||||
<span class="text-xs text-gray-600"><span class="font-bold">Please be concise and focus on what the app does.</span> No need to repeat "[App] is ...". No need to state that it is free/open-source or self-hosted (otherwise it wouldn't be packaged for YunoHost). Avoid marketing stuff like 'the most', or vague properties like 'easy', 'simple', 'lightweight'.</span>
|
||||
<span class="text-xs text-gray-600"><span class="font-bold">{{ _("Please be concise and focus on what the app does.") }}</span> {{ _("No need to repeat '[App] is ...'. No need to state that it is free/open-source or self-hosted (otherwise it wouldn't be packaged for YunoHost). Avoid marketing stuff like 'the most', or vague properties like 'easy', 'simple', 'lightweight'.") }}</span>
|
||||
|
||||
<label for="upstream" class="mt-5 block font-bold text-gray-700">Project code repository</label>
|
||||
<label for="upstream" class="mt-5 block font-bold text-gray-700">{{ _("Project code repository") }}</label>
|
||||
<input name="upstream" type="url" class="w-full mt-1 rounded-md border-gray-200 text-gray-700 shadow-sm" maxlength="150" required />
|
||||
|
||||
<label for="website" class="mt-5 block font-bold text-gray-700">Project website</label>
|
||||
<label for="website" class="mt-5 block font-bold text-gray-700">{{ _("Project website") }}</label>
|
||||
<input name="website" type="url" class="w-full mt-1 rounded-md border-gray-200 text-gray-700 shadow-sm" maxlength="150" />
|
||||
<span class="text-xs text-gray-600">Please <emph>do not</emph> just copy-paste the code repository URL. If the project has no proper website, then leave the field empty.</span>
|
||||
<span class="text-xs text-gray-600">{{ _("Please *do not* just copy-paste the code repository URL. If the project has no proper website, then leave the field empty.") }}</span>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="block mx-auto btn btn-primary mt-5 {% if user %}hover:bg-blue-700{% endif %}"
|
||||
{% if not user %}disabled{% endif %}
|
||||
>
|
||||
Submit
|
||||
{{ _("Submit") }}
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
|
BIN
store/translations/fr/LC_MESSAGES/messages.mo
Normal file
BIN
store/translations/fr/LC_MESSAGES/messages.mo
Normal file
Binary file not shown.
334
store/translations/fr/LC_MESSAGES/messages.po
Normal file
334
store/translations/fr/LC_MESSAGES/messages.po
Normal file
|
@ -0,0 +1,334 @@
|
|||
# French translations for PROJECT.
|
||||
# Copyright (C) 2023 ORGANIZATION
|
||||
# This file is distributed under the same license as the PROJECT project.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2023-09-05 20:41+0200\n"
|
||||
"PO-Revision-Date: 2023-09-05 19:50+0200\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language: fr\n"
|
||||
"Language-Team: fr <LL@li.org>\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.12.1\n"
|
||||
|
||||
#: app.py:115
|
||||
msgid "App %(app_id) not found"
|
||||
msgstr "L'app %(app_id) n'a pas été trouvée"
|
||||
|
||||
#: app.py:117
|
||||
msgid "You must be logged in to be able to star an app"
|
||||
msgstr "Vous devez être connecté·e pour mettre une app en favoris"
|
||||
|
||||
#: app.py:149
|
||||
msgid "You must be logged in to submit an app to the wishlist"
|
||||
msgstr "Vous devez être connecté·e pour proposer une app pour la liste de souhait"
|
||||
|
||||
#: app.py:158
|
||||
msgid "App name should be at least 3 characters"
|
||||
msgstr "Le nom d'app devrait contenir au moins 3 caractères"
|
||||
|
||||
#: app.py:159
|
||||
msgid "App name should be less than 30 characters"
|
||||
msgstr "Le nom d'app devrait contenir moins de 30 caractères"
|
||||
|
||||
#: app.py:160
|
||||
msgid "App description should be at least 5 characters"
|
||||
msgstr "La description de l'app devrait contenir au moins 5 caractères"
|
||||
|
||||
#: app.py:161
|
||||
msgid "App description should be less than 100 characters"
|
||||
msgstr "La description de l'app devrait contenir moins de 100 caractères"
|
||||
|
||||
#: app.py:162
|
||||
msgid "Upstream code repo URL should be at least 10 characters"
|
||||
msgstr "L'URL du dépôt de code devrait contenir au moins 10 caractères"
|
||||
|
||||
#: app.py:163
|
||||
msgid "Upstream code repo URL should be less than 150 characters"
|
||||
msgstr "L'URL du dépôt de code devrait contenir moins de 150 caractères"
|
||||
|
||||
#: app.py:164
|
||||
msgid "Website URL should be less than 150 characters"
|
||||
msgstr "L'URL du site web devrait contenir moins de 150 caractères"
|
||||
|
||||
#: app.py:165
|
||||
msgid "App name contains special characters"
|
||||
msgstr "Le nom de l'app contiens des caractères spéciaux"
|
||||
|
||||
#: app.py:182
|
||||
msgid "An entry with the name %(slug) already exists in the wishlist"
|
||||
msgstr "Une entrée nommée $(slug) existe déjà dans la liste de souhait"
|
||||
|
||||
#: app.py:201
|
||||
msgid ""
|
||||
"Failed to create the pull request to add the app to the wishlist ... "
|
||||
"please report the issue to the yunohost team"
|
||||
msgstr ""
|
||||
"Échec de la création de la demande d'intégration de l'app dans la liste "
|
||||
"de souhait ... merci de rapport le problème à l'équipe YunoHost"
|
||||
|
||||
#: app.py:234
|
||||
msgid ""
|
||||
"Your proposed app has succesfully been submitted. It must now be "
|
||||
"validated by the YunoHost team. You can track progress here: %(url)s"
|
||||
msgstr ""
|
||||
"Un demande d'intégration à la liste de souhait a bien été créée pour "
|
||||
"cette app. Elle doit maintenant être validée par l'équipe YunoHost. Vous "
|
||||
"pouvez suivre cette demande ici: %(url)s"
|
||||
|
||||
#: templates/app.html:67
|
||||
msgid "Try the demo"
|
||||
msgstr "Essayer la démo"
|
||||
|
||||
#: templates/app.html:79
|
||||
#, python-format
|
||||
msgid "Current version: %(version)s"
|
||||
msgstr "Version actuelle: %(version)s"
|
||||
|
||||
#: templates/app.html:81
|
||||
#, python-format
|
||||
msgid "Potential alternative to: %(alternatives)s"
|
||||
msgstr "Alternative potentielle à : %(alternatives)s"
|
||||
|
||||
#: templates/app.html:92
|
||||
#, python-format
|
||||
msgid "This app is only compatible with these specific architectures: %(archs)s"
|
||||
msgstr ""
|
||||
"Cette app est uniquement compatible avec les architectures suivantes : "
|
||||
"%(archs)s"
|
||||
|
||||
#: templates/app.html:98
|
||||
#, python-format
|
||||
msgid "This app requires an unusual amount of RAM to install: %(ram)s"
|
||||
msgstr ""
|
||||
"Cette app requiert une quantité inhabituelle de RAM pour être installée :"
|
||||
" %(ram)s"
|
||||
|
||||
#: templates/app.html:104
|
||||
msgid "Important infos before installing"
|
||||
msgstr "Informations importantes avant l'installation"
|
||||
|
||||
#: templates/app.html:110
|
||||
msgid "Anti-features"
|
||||
msgstr "Anti-fonctionnalités"
|
||||
|
||||
#: templates/app.html:111
|
||||
msgid "(This app has features you may not like)"
|
||||
msgstr "(Cette app a des spécificités que vous pourriez ne pas aimer)"
|
||||
|
||||
#: templates/app.html:122
|
||||
msgid "Useful links"
|
||||
msgstr "Liens utiles"
|
||||
|
||||
#: templates/app.html:125
|
||||
#, python-format
|
||||
msgid "License: %(license)s"
|
||||
msgstr "Licence: %(license)s"
|
||||
|
||||
#: templates/app.html:126
|
||||
msgid " Official website"
|
||||
msgstr "Site officiel"
|
||||
|
||||
#: templates/app.html:127
|
||||
msgid "Official admin documentation"
|
||||
msgstr "Documentation officielle pour les admins"
|
||||
|
||||
#: templates/app.html:128
|
||||
msgid "Official user documentation"
|
||||
msgstr "Documentation officielle pour les utilisateur·ice·s"
|
||||
|
||||
#: templates/app.html:129
|
||||
msgid "Official code repository"
|
||||
msgstr "Dépôt de code officiel"
|
||||
|
||||
#: templates/app.html:130
|
||||
msgid "YunoHost package repository"
|
||||
msgstr "Dépôt de code du paquet YunoHost"
|
||||
|
||||
#: templates/base.html:5
|
||||
msgid "YunoHost app store"
|
||||
msgstr "Store d'apps de YunoHost"
|
||||
|
||||
#: templates/base.html:56
|
||||
msgid "Home"
|
||||
msgstr "Accueil"
|
||||
|
||||
#: templates/base.html:65
|
||||
msgid "Catalog"
|
||||
msgstr "Catalogue"
|
||||
|
||||
#: templates/base.html:71
|
||||
msgid "Wishlist"
|
||||
msgstr "Liste de souhaits"
|
||||
|
||||
#: templates/base.html:84
|
||||
msgid "YunoHost documentation"
|
||||
msgstr "Documentation YunoHost"
|
||||
|
||||
#: templates/base.html:91
|
||||
msgid "Login using YunoHost's forum"
|
||||
msgstr "Se connecter via le forum YunoHost"
|
||||
|
||||
#: templates/base.html:98
|
||||
msgid "Menu"
|
||||
msgstr "Menu"
|
||||
|
||||
#: templates/base.html:123
|
||||
msgid "Toggle menu"
|
||||
msgstr "Activer le menu"
|
||||
|
||||
#: templates/catalog.html:74
|
||||
msgid "Application Catalog"
|
||||
msgstr "Catalogue d'applications"
|
||||
|
||||
#: templates/catalog.html:80 templates/wishlist.html:12
|
||||
msgid "Search"
|
||||
msgstr "Recherche"
|
||||
|
||||
#: templates/catalog.html:85 templates/wishlist.html:17
|
||||
msgid "Search for..."
|
||||
msgstr "Rechercher..."
|
||||
|
||||
#: templates/catalog.html:101
|
||||
msgid "All apps"
|
||||
msgstr "Toutes les apps"
|
||||
|
||||
#: templates/catalog.html:112
|
||||
msgid "Sort by"
|
||||
msgstr "Trier par"
|
||||
|
||||
#: templates/catalog.html:118
|
||||
msgid "Alphabetical"
|
||||
msgstr "Alphabétique"
|
||||
|
||||
#: templates/catalog.html:119
|
||||
msgid "Newest"
|
||||
msgstr "Nouveauté"
|
||||
|
||||
#: templates/catalog.html:120 templates/wishlist.html:47
|
||||
msgid "Popularity"
|
||||
msgstr "Popularité"
|
||||
|
||||
#: templates/catalog.html:133
|
||||
msgid "Show only apps you starred"
|
||||
msgstr "Montrer uniquement mes favoris"
|
||||
|
||||
#: templates/catalog.html:149
|
||||
msgid "No results found."
|
||||
msgstr "Aucun résultat trouvé."
|
||||
|
||||
#: templates/catalog.html:152
|
||||
msgid "Not finding what you are looking for?"
|
||||
msgstr "Vous ne trouvez pas ce que vous cherchez ?"
|
||||
|
||||
#: templates/catalog.html:153
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr "Jetez un oeil à la liste de souhait !"
|
||||
|
||||
#: templates/catalog.html:159
|
||||
msgid "Applications currently flagged as broken or low-quality"
|
||||
msgstr "Applications actuellement marquées comme cassées ou de mauvaise qualité"
|
||||
|
||||
#: templates/catalog.html:162
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr "Il s'agit d'apps qui n'ont pas validé nos tests automatisés."
|
||||
|
||||
#: templates/catalog.html:163
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
msgstr ""
|
||||
"Il s'agit généralement d'une situation temporaire qui requiert que des "
|
||||
"packageur·euse·s corrigent un problème dans l'app."
|
||||
|
||||
#: templates/index.html:7
|
||||
msgid "Application Store"
|
||||
msgstr "Store d'application"
|
||||
|
||||
#: templates/index.html:18
|
||||
msgid "Browse all applications"
|
||||
msgstr "Toutes les applications"
|
||||
|
||||
#: templates/wishlist.html:5
|
||||
msgid "Application Wishlist"
|
||||
msgstr "Liste de souhait d'applications"
|
||||
|
||||
#: templates/wishlist.html:28
|
||||
msgid "Suggest an app"
|
||||
msgstr "Suggérer une app"
|
||||
|
||||
#: templates/wishlist.html:40 templates/wishlist_add.html:53
|
||||
msgid "Name"
|
||||
msgstr "Nom"
|
||||
|
||||
#: templates/wishlist.html:43 templates/wishlist_add.html:56
|
||||
msgid "Description"
|
||||
msgstr "Description"
|
||||
|
||||
#: templates/wishlist_add.html:5
|
||||
msgid "Suggest an application to be added to YunoHost's catalog"
|
||||
msgstr "Suggérer une application à ajouter dans le catalogue de YunoHost"
|
||||
|
||||
#: templates/wishlist_add.html:26
|
||||
msgid "You must first login to be allowed to submit an app to the wishlist"
|
||||
msgstr "Vous devez être connecté·e pour proposer une app pour la liste de souhait"
|
||||
|
||||
#: templates/wishlist_add.html:34
|
||||
msgid "Please check the license of the app your are proposing"
|
||||
msgstr "Merci de vérifier la licence de l'app que vous proposez"
|
||||
|
||||
#: templates/wishlist_add.html:37
|
||||
msgid ""
|
||||
"The YunoHost project will only package free/open-source software (with "
|
||||
"possible case-by-case exceptions for apps which are not-totally-free)"
|
||||
msgstr ""
|
||||
"Le projet YunoHost intègrera uniquement des logiciels libre/open-source "
|
||||
"(avec quelques possibles exceptions au cas-par-cas pour des apps qui ne "
|
||||
"sont pas entièrement libres)"
|
||||
|
||||
#: templates/wishlist_add.html:58
|
||||
msgid "Please be concise and focus on what the app does."
|
||||
msgstr "Prière de rester concis et de se concentrer sur ce que l'app fait."
|
||||
|
||||
#: templates/wishlist_add.html:58
|
||||
msgid ""
|
||||
"No need to repeat '[App] is ...'. No need to state that it is free/open-"
|
||||
"source or self-hosted (otherwise it wouldn't be packaged for YunoHost). "
|
||||
"Avoid marketing stuff like 'the most', or vague properties like 'easy', "
|
||||
"'simple', 'lightweight'."
|
||||
msgstr ""
|
||||
"Il n'est pas nécessaire de répéter '[App] est ...', ni que l'app est "
|
||||
"libre/open-source (sinon, elle ne serait pas intégrable au catalogue). "
|
||||
"Évitez les formulations marketing type 'le meilleur', ou les propriétés "
|
||||
"vagues telles que 'facile', 'simple', 'léger'."
|
||||
|
||||
#: templates/wishlist_add.html:60
|
||||
msgid "Project code repository"
|
||||
msgstr "Dépôt de code officiel"
|
||||
|
||||
#: templates/wishlist_add.html:63
|
||||
msgid "Project website"
|
||||
msgstr "Site officiel"
|
||||
|
||||
#: templates/wishlist_add.html:65
|
||||
msgid ""
|
||||
"Please *do not* just copy-paste the code repository URL. If the project "
|
||||
"has no proper website, then leave the field empty."
|
||||
msgstr ""
|
||||
"Prière de ne pas juste copier-coller l'URL du dépôt de code. Si le projet"
|
||||
" n'a pas de vrai site web, laissez le champ vide."
|
||||
|
||||
#: templates/wishlist_add.html:72
|
||||
msgid "Submit"
|
||||
msgstr "Envoyer"
|
||||
|
||||
#~ msgid "Add an app to the wishlist"
|
||||
#~ msgstr "Ajouter une app à la liste"
|
||||
|
Loading…
Add table
Reference in a new issue