mirror of
https://github.com/LibreTranslate/LibreTranslate.git
synced 2024-11-19 22:10:09 +01:00
commit
cb3ee55eb4
2
.github/workflows/publish-package.yml
vendored
2
.github/workflows/publish-package.yml
vendored
@ -26,6 +26,7 @@ jobs:
|
||||
python -m pip install --upgrade pip
|
||||
pip install pytest flake8
|
||||
pip install .
|
||||
python compile_locales.py
|
||||
|
||||
- name: Check code style with flake8 (lint)
|
||||
run: |
|
||||
@ -60,5 +61,6 @@ jobs:
|
||||
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
|
||||
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
|
||||
run: |
|
||||
python compile_locales.py
|
||||
python setup.py sdist bdist_wheel
|
||||
twine upload dist/*
|
||||
|
@ -14,11 +14,11 @@ RUN python -mvenv venv && ./venv/bin/pip install --upgrade pip
|
||||
|
||||
COPY . .
|
||||
|
||||
# Install package from source code
|
||||
RUN ./venv/bin/pip install . \
|
||||
# Install package from source code, compile translations
|
||||
RUN ./venv/bin/pip install Babel==2.11.0 && ./venv/bin/python compile_locales.py \
|
||||
&& ./venv/bin/pip install . \
|
||||
&& ./venv/bin/pip cache purge
|
||||
|
||||
|
||||
FROM python:3.8.14-slim-bullseye
|
||||
|
||||
ARG with_models=false
|
||||
|
16
compile_locales.py
Executable file
16
compile_locales.py
Executable file
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env python
|
||||
import sys
|
||||
import os
|
||||
from babel.messages.frontend import main as pybabel
|
||||
|
||||
if __name__ == "__main__":
|
||||
locales_dir = os.path.join("libretranslate", "locales")
|
||||
if not os.path.isdir(locales_dir):
|
||||
os.makedirs(locales_dir)
|
||||
|
||||
print("Compiling locales")
|
||||
sys.argv = ["", "compile", "-f", "-d", locales_dir]
|
||||
pybabel()
|
||||
|
||||
|
||||
|
@ -34,7 +34,8 @@ RUN if [ "$with_models" = "true" ]; then \
|
||||
fi
|
||||
|
||||
# Install package from source code
|
||||
RUN pip3 install . \
|
||||
RUN pip3 install Babel==2.11.0 && python3 compile_locales.py \
|
||||
&& pip3 install . \
|
||||
&& pip3 cache purge
|
||||
|
||||
# Depending on your cuda install you may need to uncomment this line to allow the container to access the cuda libraries
|
||||
|
@ -9,15 +9,19 @@ from timeit import default_timer
|
||||
import argostranslatefiles
|
||||
from argostranslatefiles import get_supported_formats
|
||||
from flask import (abort, Blueprint, Flask, jsonify, render_template, request,
|
||||
Response, send_file, url_for)
|
||||
Response, send_file, url_for, session)
|
||||
from flask_swagger import swagger
|
||||
from flask_swagger_ui import get_swaggerui_blueprint
|
||||
from flask_session import Session
|
||||
from translatehtml import translate_html
|
||||
from werkzeug.utils import secure_filename
|
||||
from werkzeug.exceptions import HTTPException
|
||||
from flask_babel import Babel
|
||||
|
||||
from libretranslate import flood, remove_translated_files, security
|
||||
from libretranslate.language import detect_languages, improve_translation_formatting
|
||||
from libretranslate.locales import (_, _lazy, get_available_locales, get_available_locale_codes, gettext_escaped,
|
||||
gettext_html, lazy_swag, get_alternate_locale_links)
|
||||
|
||||
from .api_keys import Database, RemoteDatabase
|
||||
from .suggestions import Database as SuggestionsDatabase
|
||||
@ -53,7 +57,7 @@ def get_req_api_key():
|
||||
def get_json_dict(request):
|
||||
d = request.get_json()
|
||||
if not isinstance(d, dict):
|
||||
abort(400, description="Invalid JSON format")
|
||||
abort(400, description=_("Invalid JSON format"))
|
||||
return d
|
||||
|
||||
|
||||
@ -121,7 +125,7 @@ def create_app(args):
|
||||
# Map userdefined frontend languages to argos language object.
|
||||
if args.frontend_language_source == "auto":
|
||||
frontend_argos_language_source = type(
|
||||
"obj", (object,), {"code": "auto", "name": "Auto Detect"}
|
||||
"obj", (object,), {"code": "auto", "name": _("Auto Detect")}
|
||||
)
|
||||
else:
|
||||
frontend_argos_language_source = next(
|
||||
@ -186,7 +190,7 @@ def create_app(args):
|
||||
if args.metrics_auth_token:
|
||||
authorization = request.headers.get('Authorization')
|
||||
if authorization != "Bearer " + args.metrics_auth_token:
|
||||
abort(401, description="Unauthorized")
|
||||
abort(401, description=_("Unauthorized"))
|
||||
|
||||
registry = CollectorRegistry()
|
||||
multiprocess.MultiProcessCollector(registry)
|
||||
@ -204,7 +208,7 @@ def create_app(args):
|
||||
ip = get_remote_address()
|
||||
|
||||
if flood.is_banned(ip):
|
||||
abort(403, description="Too many request limits violations")
|
||||
abort(403, description=_("Too many request limits violations"))
|
||||
|
||||
if args.api_keys:
|
||||
ak = get_req_api_key()
|
||||
@ -213,16 +217,16 @@ def create_app(args):
|
||||
):
|
||||
abort(
|
||||
403,
|
||||
description="Invalid API key",
|
||||
description=_("Invalid API key"),
|
||||
)
|
||||
elif (
|
||||
args.require_api_key_origin
|
||||
and api_keys_db.lookup(ak) is None
|
||||
and request.headers.get("Origin") != args.require_api_key_origin
|
||||
):
|
||||
description = "Please contact the server operator to get an API key"
|
||||
description = _("Please contact the server operator to get an API key")
|
||||
if args.get_api_key_link:
|
||||
description = "Visit %s to get an API key" % args.get_api_key_link
|
||||
description = _("Visit %(url)s to get an API key", url=args.get_api_key_link)
|
||||
abort(
|
||||
403,
|
||||
description=description,
|
||||
@ -262,7 +266,7 @@ def create_app(args):
|
||||
@bp.errorhandler(429)
|
||||
def slow_down_error(e):
|
||||
flood.report(get_remote_address())
|
||||
return jsonify({"error": "Slowdown: " + str(e.description)}), 429
|
||||
return jsonify({"error": _("Slowdown:") + " " + str(e.description)}), 429
|
||||
|
||||
@bp.errorhandler(403)
|
||||
def denied(e):
|
||||
@ -274,6 +278,10 @@ def create_app(args):
|
||||
if args.disable_web_ui:
|
||||
abort(404)
|
||||
|
||||
langcode = request.args.get('lang')
|
||||
if langcode and langcode in get_available_locale_codes(not args.debug):
|
||||
session.update(preferred_lang=langcode)
|
||||
|
||||
return render_template(
|
||||
"index.html",
|
||||
gaId=args.ga_id,
|
||||
@ -283,16 +291,20 @@ def create_app(args):
|
||||
web_version=os.environ.get("LT_WEB") is not None,
|
||||
version=get_version(),
|
||||
swagger_url=SWAGGER_URL,
|
||||
url_prefix=args.url_prefix
|
||||
available_locales=[{'code': l['code'], 'name': _lazy(l['name'])} for l in get_available_locales(not args.debug)],
|
||||
current_locale=get_locale(),
|
||||
alternate_locales=get_alternate_locale_links()
|
||||
)
|
||||
|
||||
@bp.get("/javascript-licenses")
|
||||
@bp.route("/js/app.js")
|
||||
@limiter.exempt
|
||||
def javascript_licenses():
|
||||
if args.disable_web_ui:
|
||||
def appjs():
|
||||
if args.disable_web_ui:
|
||||
abort(404)
|
||||
|
||||
return render_template("javascript-licenses.html")
|
||||
return render_template("app.js.template",
|
||||
url_prefix=args.url_prefix,
|
||||
get_api_key_link=args.get_api_key_link)
|
||||
|
||||
@bp.get("/languages")
|
||||
@limiter.exempt
|
||||
@ -323,7 +335,7 @@ def create_app(args):
|
||||
type: string
|
||||
description: Supported target language codes
|
||||
"""
|
||||
return jsonify([{"code": l.code, "name": l.name, "targets": language_pairs.get(l.code, [])} for l in languages])
|
||||
return jsonify([{"code": l.code, "name": _lazy(l.name), "targets": language_pairs.get(l.code, [])} for l in languages])
|
||||
|
||||
# Add cors
|
||||
@bp.after_request
|
||||
@ -452,11 +464,11 @@ def create_app(args):
|
||||
text_format = request.values.get("format")
|
||||
|
||||
if not q:
|
||||
abort(400, description="Invalid request: missing q parameter")
|
||||
abort(400, description=_("Invalid request: missing %(name)s parameter", name='q'))
|
||||
if not source_lang:
|
||||
abort(400, description="Invalid request: missing source parameter")
|
||||
abort(400, description=_("Invalid request: missing %(name)s parameter", name='source'))
|
||||
if not target_lang:
|
||||
abort(400, description="Invalid request: missing target parameter")
|
||||
abort(400, description=_("Invalid request: missing %(name)s parameter", name='target'))
|
||||
|
||||
batch = isinstance(q, list)
|
||||
|
||||
@ -465,8 +477,7 @@ def create_app(args):
|
||||
if args.batch_limit < batch_size:
|
||||
abort(
|
||||
400,
|
||||
description="Invalid request: Request (%d) exceeds text limit (%d)"
|
||||
% (batch_size, args.batch_limit),
|
||||
description=_("Invalid request: request (%(size)s) exceeds text limit (%(limit)s)", size=batch_size, limit=args.batch_limit),
|
||||
)
|
||||
|
||||
if args.char_limit != -1:
|
||||
@ -478,8 +489,7 @@ def create_app(args):
|
||||
if args.char_limit < chars:
|
||||
abort(
|
||||
400,
|
||||
description="Invalid request: Request (%d) exceeds character limit (%d)"
|
||||
% (chars, args.char_limit),
|
||||
description=_("Invalid request: request (%(size)s) exceeds text limit (%(limit)s)", size=chars, limit=args.char_limit),
|
||||
)
|
||||
|
||||
if source_lang == "auto":
|
||||
@ -512,18 +522,18 @@ def create_app(args):
|
||||
|
||||
for idx, lang in enumerate(src_langs):
|
||||
if lang is None:
|
||||
abort(400, description="%s is not supported" % source_langs[idx])
|
||||
abort(400, description=_("%(lang)s is not supported", lang=source_langs[idx]))
|
||||
|
||||
tgt_lang = next(iter([l for l in languages if l.code == target_lang]), None)
|
||||
|
||||
if tgt_lang is None:
|
||||
abort(400, description="%s is not supported" % target_lang)
|
||||
abort(400, description=_("%(lang)s is not supported",lang=target_lang))
|
||||
|
||||
if not text_format:
|
||||
text_format = "text"
|
||||
|
||||
if text_format not in ["text", "html"]:
|
||||
abort(400, description="%s format is not supported" % text_format)
|
||||
abort(400, description=_("%(format)s format is not supported", format=text_format))
|
||||
|
||||
try:
|
||||
if batch:
|
||||
@ -531,7 +541,7 @@ def create_app(args):
|
||||
for idx, text in enumerate(q):
|
||||
translator = src_langs[idx].get_translation(tgt_lang)
|
||||
if translator is None:
|
||||
abort(400, description="%s (%s) is not available as a target language from %s (%s)" % (tgt_lang.name, tgt_lang.code, src_langs[idx].name, src_langs[idx].code))
|
||||
abort(400, description=_("%(tname)s (%(tcode)s) is not available as a target language from %(sname)s (%(scode)s)", tname=_lazy(tgt_lang.name), tcode=tgt_lang.code, sname=_lazy(src_langs[idx].name), scode=src_langs[idx].code))
|
||||
|
||||
if text_format == "html":
|
||||
translated_text = str(translate_html(translator, text))
|
||||
@ -555,7 +565,7 @@ def create_app(args):
|
||||
else:
|
||||
translator = src_langs[0].get_translation(tgt_lang)
|
||||
if translator is None:
|
||||
abort(400, description="%s (%s) is not available as a target language from %s (%s)" % (tgt_lang.name, tgt_lang.code, src_langs[0].name, src_langs[0].code))
|
||||
abort(400, description=_("%(tname)s (%(tcode)s) is not available as a target language from %(sname)s (%(scode)s)", tname=_lazy(tgt_lang.name), tcode=tgt_lang.code, sname=_lazy(src_langs[0].name), scode=src_langs[0].code))
|
||||
|
||||
if text_format == "html":
|
||||
translated_text = str(translate_html(translator, q))
|
||||
@ -576,7 +586,7 @@ def create_app(args):
|
||||
}
|
||||
)
|
||||
except Exception as e:
|
||||
abort(500, description="Cannot translate text: %s" % str(e))
|
||||
abort(500, description=_("Cannot translate text: %(text)s", text=str(e)))
|
||||
|
||||
@bp.post("/translate_file")
|
||||
@access_check
|
||||
@ -663,36 +673,36 @@ def create_app(args):
|
||||
description: Error message
|
||||
"""
|
||||
if args.disable_files_translation:
|
||||
abort(403, description="Files translation are disabled on this server.")
|
||||
abort(403, description=_("Files translation are disabled on this server."))
|
||||
|
||||
source_lang = request.form.get("source")
|
||||
target_lang = request.form.get("target")
|
||||
file = request.files['file']
|
||||
|
||||
if not file:
|
||||
abort(400, description="Invalid request: missing file parameter")
|
||||
abort(400, description=_("Invalid request: missing %(name)s parameter", name='file'))
|
||||
if not source_lang:
|
||||
abort(400, description="Invalid request: missing source parameter")
|
||||
abort(400, description=_("Invalid request: missing %(name)s parameter", name='source'))
|
||||
if not target_lang:
|
||||
abort(400, description="Invalid request: missing target parameter")
|
||||
abort(400, description=_("Invalid request: missing %(name)s parameter", name='target'))
|
||||
|
||||
if file.filename == '':
|
||||
abort(400, description="Invalid request: empty file")
|
||||
abort(400, description=_("Invalid request: empty file"))
|
||||
|
||||
if os.path.splitext(file.filename)[1] not in frontend_argos_supported_files_format:
|
||||
abort(400, description="Invalid request: file format not supported")
|
||||
abort(400, description=_("Invalid request: file format not supported"))
|
||||
|
||||
source_langs = [source_lang]
|
||||
src_langs = [next(iter([l for l in languages if l.code == source_lang]), None) for source_lang in source_langs]
|
||||
|
||||
for idx, lang in enumerate(src_langs):
|
||||
if lang is None:
|
||||
abort(400, description="%s is not supported" % source_langs[idx])
|
||||
abort(400, description=_("%(lang)s is not supported", lang=source_langs[idx]))
|
||||
|
||||
tgt_lang = next(iter([l for l in languages if l.code == target_lang]), None)
|
||||
|
||||
if tgt_lang is None:
|
||||
abort(400, description="%s is not supported" % target_lang)
|
||||
abort(400, description=_("%(lang)s is not supported", lang=target_lang))
|
||||
|
||||
try:
|
||||
filename = str(uuid.uuid4()) + '.' + secure_filename(file.filename)
|
||||
@ -717,7 +727,7 @@ def create_app(args):
|
||||
Download a translated file
|
||||
"""
|
||||
if args.disable_files_translation:
|
||||
abort(400, description="Files translation are disabled on this server.")
|
||||
abort(400, description=_("Files translation are disabled on this server."))
|
||||
|
||||
filepath = os.path.join(get_upload_dir(), filename)
|
||||
try:
|
||||
@ -725,7 +735,7 @@ def create_app(args):
|
||||
if os.path.isfile(checked_filepath):
|
||||
filepath = checked_filepath
|
||||
except security.SuspiciousFileOperation:
|
||||
abort(400, description="Invalid filename")
|
||||
abort(400, description=_("Invalid filename"))
|
||||
|
||||
return_data = io.BytesIO()
|
||||
with open(filepath, 'rb') as fo:
|
||||
@ -818,9 +828,6 @@ def create_app(args):
|
||||
type: string
|
||||
description: Error message
|
||||
"""
|
||||
if flood.is_banned(get_remote_address()):
|
||||
abort(403, description="Too many request limits violations")
|
||||
|
||||
if request.is_json:
|
||||
json = get_json_dict(request)
|
||||
q = json.get("q")
|
||||
@ -828,7 +835,7 @@ def create_app(args):
|
||||
q = request.values.get("q")
|
||||
|
||||
if not q:
|
||||
abort(400, description="Invalid request: missing q parameter")
|
||||
abort(400, description=_("Invalid request: missing %(name)s parameter", name='q'))
|
||||
|
||||
return jsonify(detect_languages(q))
|
||||
|
||||
@ -901,11 +908,11 @@ def create_app(args):
|
||||
"language": {
|
||||
"source": {
|
||||
"code": frontend_argos_language_source.code,
|
||||
"name": frontend_argos_language_source.name,
|
||||
"name": _lazy(frontend_argos_language_source.name),
|
||||
},
|
||||
"target": {
|
||||
"code": frontend_argos_language_target.code,
|
||||
"name": frontend_argos_language_target.name,
|
||||
"name": _lazy(frontend_argos_language_target.name),
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -969,7 +976,7 @@ def create_app(args):
|
||||
description: Error message
|
||||
"""
|
||||
if not args.suggestions:
|
||||
abort(403, description="Suggestions are disabled on this server.")
|
||||
abort(403, description=_("Suggestions are disabled on this server."))
|
||||
|
||||
q = request.values.get("q")
|
||||
s = request.values.get("s")
|
||||
@ -977,18 +984,23 @@ def create_app(args):
|
||||
target_lang = request.values.get("target")
|
||||
|
||||
if not q:
|
||||
abort(400, description="Invalid request: missing q parameter")
|
||||
abort(400, description=_("Invalid request: missing %(name)s parameter", name='q'))
|
||||
if not s:
|
||||
abort(400, description="Invalid request: missing s parameter")
|
||||
abort(400, description=_("Invalid request: missing %(name)s parameter", name='s'))
|
||||
if not source_lang:
|
||||
abort(400, description="Invalid request: missing source parameter")
|
||||
abort(400, description=_("Invalid request: missing %(name)s parameter", name='source'))
|
||||
if not target_lang:
|
||||
abort(400, description="Invalid request: missing target parameter")
|
||||
abort(400, description=_("Invalid request: missing %(name)s parameter", name='target'))
|
||||
|
||||
SuggestionsDatabase().add(q, s, source_lang, target_lang)
|
||||
return jsonify({"success": True})
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
app.config["SESSION_TYPE"] = "filesystem"
|
||||
app.config["SESSION_FILE_DIR"] = os.path.join("db", "sessions")
|
||||
Session(app)
|
||||
|
||||
if args.debug:
|
||||
app.config["TEMPLATES_AUTO_RELOAD"] = True
|
||||
if args.url_prefix:
|
||||
@ -1002,11 +1014,21 @@ def create_app(args):
|
||||
swag["info"]["version"] = get_version()
|
||||
swag["info"]["title"] = "LibreTranslate"
|
||||
|
||||
|
||||
@app.route(API_URL)
|
||||
@limiter.exempt
|
||||
def spec():
|
||||
return jsonify(swag)
|
||||
return jsonify(lazy_swag(swag))
|
||||
|
||||
app.config["BABEL_TRANSLATION_DIRECTORIES"] = 'locales'
|
||||
babel = Babel(app)
|
||||
@babel.localeselector
|
||||
def get_locale():
|
||||
override_lang = request.headers.get('X-Override-Accept-Language')
|
||||
if override_lang and override_lang in get_available_locale_codes():
|
||||
return override_lang
|
||||
return session.get('preferred_lang', request.accept_languages.best_match(get_available_locale_codes()))
|
||||
|
||||
app.jinja_env.globals.update(_e=gettext_escaped, _h=gettext_html)
|
||||
|
||||
# Call factory function to create our blueprint
|
||||
swaggerui_blueprint = get_swaggerui_blueprint(SWAGGER_URL, API_URL)
|
||||
|
84
libretranslate/locales.py
Normal file
84
libretranslate/locales.py
Normal file
@ -0,0 +1,84 @@
|
||||
import os
|
||||
import json
|
||||
from functools import lru_cache
|
||||
from flask_babel import gettext as _
|
||||
from flask_babel import lazy_gettext as _lazy
|
||||
|
||||
from markupsafe import escape, Markup
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def get_available_locales(only_reviewed=True):
|
||||
locales_dir = os.path.join(os.path.dirname(__file__), 'locales')
|
||||
dirs = [os.path.join(locales_dir, d) for d in os.listdir(locales_dir)]
|
||||
|
||||
res = [{'code': 'en', 'name': 'English'}]
|
||||
|
||||
for d in dirs:
|
||||
meta_file = os.path.join(d, 'meta.json')
|
||||
if os.path.isdir(os.path.join(d, 'LC_MESSAGES')) and os.path.isfile(meta_file):
|
||||
try:
|
||||
with open(meta_file) as f:
|
||||
j = json.loads(f.read())
|
||||
except Exception as e:
|
||||
print(e)
|
||||
continue
|
||||
|
||||
if j.get('reviewed') or not only_reviewed:
|
||||
res.append({'code': os.path.basename(d), 'name': j.get('name', '')})
|
||||
|
||||
return res
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def get_available_locale_codes(only_reviewed=True):
|
||||
return [l['code'] for l in get_available_locales(only_reviewed=only_reviewed)]
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def get_alternate_locale_links():
|
||||
tmpl = os.environ.get("LT_LOCALE_LINK_TEMPLATE")
|
||||
if tmpl is None:
|
||||
return []
|
||||
|
||||
locales = get_available_locale_codes()
|
||||
result = []
|
||||
for l in locales:
|
||||
link = tmpl.replace("{LANG}", l)
|
||||
if l == 'en':
|
||||
link = link.replace("en.", "")
|
||||
result.append({ 'link': link,'lang': l })
|
||||
return result
|
||||
|
||||
# Javascript code should use _e instead of _
|
||||
def gettext_escaped(text, **variables):
|
||||
return json.dumps(_(text, **variables))
|
||||
|
||||
# HTML should be escaped using _h instead of _
|
||||
def gettext_html(text, **variables):
|
||||
# Translate text without args
|
||||
s = str(escape(_(text)))
|
||||
|
||||
v = {}
|
||||
if variables:
|
||||
for k in variables:
|
||||
if hasattr(variables[k], 'unescape'):
|
||||
v[k] = variables[k].unescape()
|
||||
else:
|
||||
v[k] = Markup(variables[k])
|
||||
|
||||
# Variables are assumed to be already escaped and thus safe
|
||||
return Markup(s if not v else s % v)
|
||||
|
||||
def swag_eval(swag, func):
|
||||
# Traverse the swag spec structure
|
||||
# and call func on summary and description keys
|
||||
for k in swag:
|
||||
if k in ['summary', 'description'] and isinstance(swag[k], str) and swag[k] != "":
|
||||
swag[k] = func(swag[k])
|
||||
elif k == 'tags' and isinstance(swag[k], list):
|
||||
swag[k] = [func(v) for v in swag[k]]
|
||||
elif isinstance(swag[k], dict):
|
||||
swag_eval(swag[k], func)
|
||||
|
||||
return swag
|
||||
|
||||
def lazy_swag(swag):
|
||||
return swag_eval(swag, _lazy)
|
3
libretranslate/locales/.gitignore
vendored
Normal file
3
libretranslate/locales/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
**/*.mo
|
||||
.langs.py
|
||||
.swag.py
|
590
libretranslate/locales/de/LC_MESSAGES/messages.po
Normal file
590
libretranslate/locales/de/LC_MESSAGES/messages.po
Normal file
@ -0,0 +1,590 @@
|
||||
# German translations for LibreTranslate.
|
||||
# Copyright (C) 2023 LibreTranslate Authors
|
||||
# This file is distributed under the same license as the LibreTranslate
|
||||
# project.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: LibreTranslate 1.3.9\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2023-01-06 14:26-0500\n"
|
||||
"PO-Revision-Date: 2023-01-06 14:26-0500\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language: de\n"
|
||||
"Language-Team: de <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.11.0\n"
|
||||
|
||||
#: libretranslate/app.py:60
|
||||
msgid "Invalid JSON format"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/app.py:128 libretranslate/templates/app.js.template:427
|
||||
msgid "Auto Detect"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/app.py:193
|
||||
msgid "Unauthorized"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/app.py:211
|
||||
msgid "Too many request limits violations"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/app.py:220
|
||||
msgid "Invalid API key"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/app.py:227
|
||||
msgid "Please contact the server operator to get an API key"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/app.py:229
|
||||
#, python-format
|
||||
msgid "Visit %(url)s to get an API key"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/app.py:269
|
||||
msgid "Slowdown:"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/app.py:467 libretranslate/app.py:469
|
||||
#: libretranslate/app.py:471 libretranslate/app.py:683
|
||||
#: libretranslate/app.py:685 libretranslate/app.py:687
|
||||
#: libretranslate/app.py:838 libretranslate/app.py:987
|
||||
#: libretranslate/app.py:989 libretranslate/app.py:991
|
||||
#: libretranslate/app.py:993
|
||||
#, python-format
|
||||
msgid "Invalid request: missing %(name)s parameter"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/app.py:480 libretranslate/app.py:492
|
||||
#, python-format
|
||||
msgid "Invalid request: request (%(size)s) exceeds text limit (%(limit)s)"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/app.py:525 libretranslate/app.py:530
|
||||
#: libretranslate/app.py:700 libretranslate/app.py:705
|
||||
#, python-format
|
||||
msgid "%(lang)s is not supported"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/app.py:536
|
||||
#, python-format
|
||||
msgid "%(format)s format is not supported"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/app.py:544 libretranslate/app.py:568
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(tname)s (%(tcode)s) is not available as a target language from "
|
||||
"%(sname)s (%(scode)s)"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/app.py:589
|
||||
#, python-format
|
||||
msgid "Cannot translate text: %(text)s"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/app.py:676 libretranslate/app.py:730
|
||||
msgid "Files translation are disabled on this server."
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/app.py:690
|
||||
msgid "Invalid request: empty file"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/app.py:693
|
||||
msgid "Invalid request: file format not supported"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/app.py:738
|
||||
msgid "Invalid filename"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/app.py:979
|
||||
msgid "Suggestions are disabled on this server."
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:1
|
||||
msgid "English"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:2
|
||||
msgid "Arabic"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:3
|
||||
msgid "Azerbaijani"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:4
|
||||
msgid "Chinese"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:5
|
||||
msgid "Czech"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:6
|
||||
msgid "Danish"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:7
|
||||
msgid "Dutch"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:8
|
||||
msgid "Esperanto"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:9
|
||||
msgid "Finnish"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:10
|
||||
msgid "French"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:11
|
||||
msgid "German"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:12
|
||||
msgid "Greek"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:13
|
||||
msgid "Hebrew"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:14
|
||||
msgid "Hindi"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:15
|
||||
msgid "Hungarian"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:16
|
||||
msgid "Indonesian"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:17
|
||||
msgid "Irish"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:18
|
||||
msgid "Italian"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:19
|
||||
msgid "Japanese"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:20
|
||||
msgid "Korean"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:21
|
||||
msgid "Persian"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:22
|
||||
msgid "Polish"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:23
|
||||
msgid "Portuguese"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:24
|
||||
msgid "Russian"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:25
|
||||
msgid "Slovak"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:26
|
||||
msgid "Spanish"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:27
|
||||
msgid "Swedish"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:28
|
||||
msgid "Turkish"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:29
|
||||
msgid "Ukranian"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.langs.py:30
|
||||
msgid "Vietnamese"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:1
|
||||
msgid "Retrieve list of supported languages"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:2
|
||||
msgid "List of languages"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:3
|
||||
msgid "translate"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:4
|
||||
msgid "Translate text from a language to another"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:5 libretranslate/templates/index.html:219
|
||||
msgid "Translated text"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:6
|
||||
msgid "Invalid request"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:7
|
||||
msgid "Translation error"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:8
|
||||
msgid "Slow down"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:9
|
||||
msgid "Banned"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:10
|
||||
msgid "Translate file from a language to another"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:11
|
||||
msgid "Translated file"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:12
|
||||
msgid "Detect the language of a single text"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:13
|
||||
msgid "Detections"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:14
|
||||
msgid "Detection error"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:15
|
||||
msgid "Retrieve frontend specific settings"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:16
|
||||
msgid "frontend settings"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:17
|
||||
msgid "frontend"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:18
|
||||
msgid "Submit a suggestion to improve a translation"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:19
|
||||
msgid "Success"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:20
|
||||
msgid "Not authorized"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:21
|
||||
msgid "feedback"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:22
|
||||
msgid "Language code"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:23
|
||||
msgid "Human-readable language name (in English)"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:24
|
||||
msgid "Supported target language codes"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:25
|
||||
msgid "Translated text(s)"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:26
|
||||
msgid "Error message"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:27
|
||||
msgid "Reason for slow down"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:28
|
||||
msgid "Translated file url"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:29
|
||||
msgid "Confidence value"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:30
|
||||
msgid "Character input limit for this language (-1 indicates no limit)"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:31
|
||||
msgid "Frontend translation timeout"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:32
|
||||
msgid "Whether the API key database is enabled."
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:33
|
||||
msgid "Whether an API key is required."
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:34
|
||||
msgid "Whether submitting suggestions is enabled."
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:35
|
||||
msgid "Supported files format"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/locales/.swag.py:36
|
||||
msgid "Whether submission was successful"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/app.js.template:31
|
||||
#: libretranslate/templates/app.js.template:275
|
||||
#: libretranslate/templates/app.js.template:279
|
||||
msgid "Copy text"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/app.js.template:72
|
||||
#: libretranslate/templates/app.js.template:78
|
||||
#: libretranslate/templates/app.js.template:83
|
||||
#: libretranslate/templates/app.js.template:262
|
||||
#: libretranslate/templates/app.js.template:332
|
||||
#: libretranslate/templates/app.js.template:402
|
||||
#: libretranslate/templates/app.js.template:447
|
||||
#, python-format
|
||||
msgid "Cannot load %(url)s"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/app.js.template:253
|
||||
#: libretranslate/templates/app.js.template:323
|
||||
#: libretranslate/templates/app.js.template:385
|
||||
#: libretranslate/templates/app.js.template:395
|
||||
msgid "Unknown error"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/app.js.template:276
|
||||
msgid "Copied"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/app.js.template:320
|
||||
msgid ""
|
||||
"Thanks for your correction. Note the suggestion will not take effect "
|
||||
"right away."
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/app.js.template:423
|
||||
msgid "No languages available. Did you install the models correctly?"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/app.js.template:479
|
||||
#, python-format
|
||||
msgid "Type in your API Key. If you need an API key, %(instructions)s"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/app.js.template:479
|
||||
msgid "press the \"Get API Key\" link."
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/app.js.template:479
|
||||
msgid "contact the server operator."
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:8 libretranslate/templates/index.html:25
|
||||
#: libretranslate/templates/index.html:333
|
||||
msgid "Free and Open Source Machine Translation API"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:10
|
||||
#: libretranslate/templates/index.html:29
|
||||
msgid ""
|
||||
"Free and Open Source Machine Translation API. Self-hosted, offline "
|
||||
"capable and easy to setup. Run your own API server in just a few minutes."
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:11
|
||||
msgid "translation"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:11
|
||||
msgid "api"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:64
|
||||
msgid "API Docs"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:66
|
||||
msgid "Get API Key"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:68
|
||||
msgid "GitHub"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:70
|
||||
msgid "Set API Key"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:72
|
||||
msgid "Change language"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:78
|
||||
msgid "Edit"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:154
|
||||
msgid "Dismiss"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:168
|
||||
msgid "Translation API"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:172
|
||||
msgid "Translate Text"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:176
|
||||
msgid "Translate Files"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:182
|
||||
msgid "Translate from"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:192
|
||||
msgid "Swap source and target languages"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:195
|
||||
msgid "Translate into"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:207
|
||||
msgid "Text to translate"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:210
|
||||
msgid "Delete text"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:223
|
||||
msgid "Suggest translation"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:227
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:230
|
||||
msgid "Send"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:246
|
||||
msgid "Supported file formats:"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:250
|
||||
msgid "File"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:265
|
||||
msgid "Remove file"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:272
|
||||
msgid "Translate"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:273
|
||||
#: libretranslate/templates/index.html:317
|
||||
msgid "Download"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:292
|
||||
msgid "Request"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:297
|
||||
msgid "Response"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:312
|
||||
msgid "Open Source Machine Translation API"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:313
|
||||
msgid "Self-Hosted. Offline Capable. Easy to Setup."
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:332
|
||||
msgid "LibreTranslate"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:334
|
||||
msgid "License:"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:337
|
||||
#, python-format
|
||||
msgid ""
|
||||
"This public API should be used for testing, personal or infrequent use. "
|
||||
"If you're going to run an application in production, please "
|
||||
"%(host_server)s or %(get_api_key)s."
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:337
|
||||
msgid "host your own server"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:337
|
||||
msgid "get an API key"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:345
|
||||
#, python-format
|
||||
msgid "Made with %(heart)s by %(contributors)s and powered by %(engine)s"
|
||||
msgstr ""
|
||||
|
||||
#: libretranslate/templates/index.html:345
|
||||
#, python-format
|
||||
msgid "%(libretranslate)s Contributors"
|
||||
msgstr ""
|
||||
|
4
libretranslate/locales/de/meta.json
Normal file
4
libretranslate/locales/de/meta.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "German",
|
||||
"reviewed": false
|
||||
}
|
606
libretranslate/locales/fr/LC_MESSAGES/messages.po
Normal file
606
libretranslate/locales/fr/LC_MESSAGES/messages.po
Normal file
@ -0,0 +1,606 @@
|
||||
# French translations for LibreTranslate.
|
||||
# Copyright (C) 2023 LibreTranslate Authors
|
||||
# This file is distributed under the same license as the LibreTranslate
|
||||
# project.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: LibreTranslate 1.3.9\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2023-01-06 14:26-0500\n"
|
||||
"PO-Revision-Date: 2023-01-06 14:26-0500\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: fr <LL@li.org>\n"
|
||||
"Language: fr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
"Generated-By: Babel 2.11.0\n"
|
||||
|
||||
#: libretranslate/app.py:60
|
||||
msgid "Invalid JSON format"
|
||||
msgstr "Format JSON invalide"
|
||||
|
||||
#: libretranslate/app.py:128 libretranslate/templates/app.js.template:427
|
||||
msgid "Auto Detect"
|
||||
msgstr "Auto Detect"
|
||||
|
||||
#: libretranslate/app.py:193
|
||||
msgid "Unauthorized"
|
||||
msgstr "Non autorisé"
|
||||
|
||||
#: libretranslate/app.py:211
|
||||
msgid "Too many request limits violations"
|
||||
msgstr "Trop de demandes limitent les violations"
|
||||
|
||||
#: libretranslate/app.py:220
|
||||
msgid "Invalid API key"
|
||||
msgstr "Clé API invalide"
|
||||
|
||||
#: libretranslate/app.py:227
|
||||
msgid "Please contact the server operator to get an API key"
|
||||
msgstr "Veuillez contacter l'opérateur du serveur pour obtenir une clé API"
|
||||
|
||||
#: libretranslate/app.py:229
|
||||
#, python-format
|
||||
msgid "Visit %(url)s to get an API key"
|
||||
msgstr "Visite %(url)s pour obtenir une clé API"
|
||||
|
||||
#: libretranslate/app.py:269
|
||||
msgid "Slowdown:"
|
||||
msgstr "Ralentissement :"
|
||||
|
||||
#: libretranslate/app.py:467 libretranslate/app.py:469
|
||||
#: libretranslate/app.py:471 libretranslate/app.py:683
|
||||
#: libretranslate/app.py:685 libretranslate/app.py:687
|
||||
#: libretranslate/app.py:838 libretranslate/app.py:987
|
||||
#: libretranslate/app.py:989 libretranslate/app.py:991
|
||||
#: libretranslate/app.py:993
|
||||
#, python-format
|
||||
msgid "Invalid request: missing %(name)s parameter"
|
||||
msgstr "Demande invalide: manquante %(name)s paramètre"
|
||||
|
||||
#: libretranslate/app.py:480 libretranslate/app.py:492
|
||||
#, python-format
|
||||
msgid "Invalid request: request (%(size)s) exceeds text limit (%(limit)s)"
|
||||
msgstr ""
|
||||
"Demande non valide : demande (%(size)s) dépasse la limite de texte "
|
||||
"(%(limit)s)"
|
||||
|
||||
#: libretranslate/app.py:525 libretranslate/app.py:530
|
||||
#: libretranslate/app.py:700 libretranslate/app.py:705
|
||||
#, python-format
|
||||
msgid "%(lang)s is not supported"
|
||||
msgstr "%(lang)s n &apos; est pas soutenue"
|
||||
|
||||
#: libretranslate/app.py:536
|
||||
#, python-format
|
||||
msgid "%(format)s format is not supported"
|
||||
msgstr "%(format)s format n'est pas supporté"
|
||||
|
||||
#: libretranslate/app.py:544 libretranslate/app.py:568
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(tname)s (%(tcode)s) is not available as a target language from %(sname)s "
|
||||
"(%(scode)s)"
|
||||
msgstr ""
|
||||
"%(tname)s (%(tcode)s) n'est pas disponible comme langue cible de %(sname)s "
|
||||
"(%(scode)s)"
|
||||
|
||||
#: libretranslate/app.py:589
|
||||
#, python-format
|
||||
msgid "Cannot translate text: %(text)s"
|
||||
msgstr "Impossible de traduire le texte: %(text)s"
|
||||
|
||||
#: libretranslate/app.py:676 libretranslate/app.py:730
|
||||
msgid "Files translation are disabled on this server."
|
||||
msgstr "La traduction de fichiers est désactivée sur ce serveur."
|
||||
|
||||
#: libretranslate/app.py:690
|
||||
msgid "Invalid request: empty file"
|
||||
msgstr "Demande invalide: fichier vide"
|
||||
|
||||
#: libretranslate/app.py:693
|
||||
msgid "Invalid request: file format not supported"
|
||||
msgstr "Demande invalide: format de fichier non supporté"
|
||||
|
||||
#: libretranslate/app.py:738
|
||||
msgid "Invalid filename"
|
||||
msgstr "Nom de fichier invalide"
|
||||
|
||||
#: libretranslate/app.py:979
|
||||
msgid "Suggestions are disabled on this server."
|
||||
msgstr "Les suggestions sont désactivées sur ce serveur."
|
||||
|
||||
#: libretranslate/locales/.langs.py:1
|
||||
msgid "English"
|
||||
msgstr "Anglais"
|
||||
|
||||
#: libretranslate/locales/.langs.py:2
|
||||
msgid "Arabic"
|
||||
msgstr "Arabe"
|
||||
|
||||
#: libretranslate/locales/.langs.py:3
|
||||
msgid "Azerbaijani"
|
||||
msgstr "Azerbaïdjan"
|
||||
|
||||
#: libretranslate/locales/.langs.py:4
|
||||
msgid "Chinese"
|
||||
msgstr "Chinois"
|
||||
|
||||
#: libretranslate/locales/.langs.py:5
|
||||
msgid "Czech"
|
||||
msgstr "Tchèque"
|
||||
|
||||
#: libretranslate/locales/.langs.py:6
|
||||
msgid "Danish"
|
||||
msgstr "Danish"
|
||||
|
||||
#: libretranslate/locales/.langs.py:7
|
||||
msgid "Dutch"
|
||||
msgstr "Néerlandais"
|
||||
|
||||
#: libretranslate/locales/.langs.py:8
|
||||
msgid "Esperanto"
|
||||
msgstr "Esperanto"
|
||||
|
||||
#: libretranslate/locales/.langs.py:9
|
||||
msgid "Finnish"
|
||||
msgstr "Finland"
|
||||
|
||||
#: libretranslate/locales/.langs.py:10
|
||||
msgid "French"
|
||||
msgstr "Français"
|
||||
|
||||
#: libretranslate/locales/.langs.py:11
|
||||
msgid "German"
|
||||
msgstr "Allemand"
|
||||
|
||||
#: libretranslate/locales/.langs.py:12
|
||||
msgid "Greek"
|
||||
msgstr "Grec"
|
||||
|
||||
#: libretranslate/locales/.langs.py:13
|
||||
msgid "Hebrew"
|
||||
msgstr "Hébreux"
|
||||
|
||||
#: libretranslate/locales/.langs.py:14
|
||||
msgid "Hindi"
|
||||
msgstr "Hindi"
|
||||
|
||||
#: libretranslate/locales/.langs.py:15
|
||||
msgid "Hungarian"
|
||||
msgstr "Hongrois"
|
||||
|
||||
#: libretranslate/locales/.langs.py:16
|
||||
msgid "Indonesian"
|
||||
msgstr "Indonésien"
|
||||
|
||||
#: libretranslate/locales/.langs.py:17
|
||||
msgid "Irish"
|
||||
msgstr "Irish"
|
||||
|
||||
#: libretranslate/locales/.langs.py:18
|
||||
msgid "Italian"
|
||||
msgstr "Italien"
|
||||
|
||||
#: libretranslate/locales/.langs.py:19
|
||||
msgid "Japanese"
|
||||
msgstr "Japonais"
|
||||
|
||||
#: libretranslate/locales/.langs.py:20
|
||||
msgid "Korean"
|
||||
msgstr "Corée"
|
||||
|
||||
#: libretranslate/locales/.langs.py:21
|
||||
msgid "Persian"
|
||||
msgstr "Perse"
|
||||
|
||||
#: libretranslate/locales/.langs.py:22
|
||||
msgid "Polish"
|
||||
msgstr "Polonais"
|
||||
|
||||
#: libretranslate/locales/.langs.py:23
|
||||
msgid "Portuguese"
|
||||
msgstr "Portugais"
|
||||
|
||||
#: libretranslate/locales/.langs.py:24
|
||||
msgid "Russian"
|
||||
msgstr "Russe"
|
||||
|
||||
#: libretranslate/locales/.langs.py:25
|
||||
msgid "Slovak"
|
||||
msgstr "Slovaquie"
|
||||
|
||||
#: libretranslate/locales/.langs.py:26
|
||||
msgid "Spanish"
|
||||
msgstr "Espagnol"
|
||||
|
||||
#: libretranslate/locales/.langs.py:27
|
||||
msgid "Swedish"
|
||||
msgstr "Suédois"
|
||||
|
||||
#: libretranslate/locales/.langs.py:28
|
||||
msgid "Turkish"
|
||||
msgstr "Turque"
|
||||
|
||||
#: libretranslate/locales/.langs.py:29
|
||||
msgid "Ukranian"
|
||||
msgstr "Ukranian"
|
||||
|
||||
#: libretranslate/locales/.langs.py:30
|
||||
msgid "Vietnamese"
|
||||
msgstr "Vietnam"
|
||||
|
||||
#: libretranslate/locales/.swag.py:1
|
||||
msgid "Retrieve list of supported languages"
|
||||
msgstr "Liste des langues supportées"
|
||||
|
||||
#: libretranslate/locales/.swag.py:2
|
||||
msgid "List of languages"
|
||||
msgstr "Liste des langues"
|
||||
|
||||
#: libretranslate/locales/.swag.py:3
|
||||
msgid "translate"
|
||||
msgstr "traduire"
|
||||
|
||||
#: libretranslate/locales/.swag.py:4
|
||||
msgid "Translate text from a language to another"
|
||||
msgstr "Traduire le texte d'une langue à une autre"
|
||||
|
||||
#: libretranslate/locales/.swag.py:5 libretranslate/templates/index.html:219
|
||||
msgid "Translated text"
|
||||
msgstr "Texte traduit"
|
||||
|
||||
#: libretranslate/locales/.swag.py:6
|
||||
msgid "Invalid request"
|
||||
msgstr "Demande non valide"
|
||||
|
||||
#: libretranslate/locales/.swag.py:7
|
||||
msgid "Translation error"
|
||||
msgstr "Erreur de traduction"
|
||||
|
||||
#: libretranslate/locales/.swag.py:8
|
||||
msgid "Slow down"
|
||||
msgstr "Doucement"
|
||||
|
||||
#: libretranslate/locales/.swag.py:9
|
||||
msgid "Banned"
|
||||
msgstr "Banned"
|
||||
|
||||
#: libretranslate/locales/.swag.py:10
|
||||
msgid "Translate file from a language to another"
|
||||
msgstr "Translate file from a language to another"
|
||||
|
||||
#: libretranslate/locales/.swag.py:11
|
||||
msgid "Translated file"
|
||||
msgstr "Fichier traduit"
|
||||
|
||||
#: libretranslate/locales/.swag.py:12
|
||||
msgid "Detect the language of a single text"
|
||||
msgstr "Detect the language of a single text"
|
||||
|
||||
#: libretranslate/locales/.swag.py:13
|
||||
msgid "Detections"
|
||||
msgstr "Détections"
|
||||
|
||||
#: libretranslate/locales/.swag.py:14
|
||||
msgid "Detection error"
|
||||
msgstr "Erreur de détection"
|
||||
|
||||
#: libretranslate/locales/.swag.py:15
|
||||
msgid "Retrieve frontend specific settings"
|
||||
msgstr "Récupérer les paramètres spécifiques du frontend"
|
||||
|
||||
#: libretranslate/locales/.swag.py:16
|
||||
msgid "frontend settings"
|
||||
msgstr "paramètres de frontend"
|
||||
|
||||
#: libretranslate/locales/.swag.py:17
|
||||
msgid "frontend"
|
||||
msgstr "frontend"
|
||||
|
||||
#: libretranslate/locales/.swag.py:18
|
||||
msgid "Submit a suggestion to improve a translation"
|
||||
msgstr "Soumettre une suggestion pour améliorer la traduction"
|
||||
|
||||
#: libretranslate/locales/.swag.py:19
|
||||
msgid "Success"
|
||||
msgstr "Succès"
|
||||
|
||||
#: libretranslate/locales/.swag.py:20
|
||||
msgid "Not authorized"
|
||||
msgstr "Non autorisé"
|
||||
|
||||
#: libretranslate/locales/.swag.py:21
|
||||
msgid "feedback"
|
||||
msgstr "rétroaction"
|
||||
|
||||
#: libretranslate/locales/.swag.py:22
|
||||
msgid "Language code"
|
||||
msgstr "Code de langue"
|
||||
|
||||
#: libretranslate/locales/.swag.py:23
|
||||
msgid "Human-readable language name (in English)"
|
||||
msgstr "Nom de langue lisible (en anglais)"
|
||||
|
||||
#: libretranslate/locales/.swag.py:24
|
||||
msgid "Supported target language codes"
|
||||
msgstr "Codes linguistiques ciblés appuyés"
|
||||
|
||||
#: libretranslate/locales/.swag.py:25
|
||||
msgid "Translated text(s)"
|
||||
msgstr "Texte(s) traduit(s)"
|
||||
|
||||
#: libretranslate/locales/.swag.py:26
|
||||
msgid "Error message"
|
||||
msgstr "Message d ' erreur"
|
||||
|
||||
#: libretranslate/locales/.swag.py:27
|
||||
msgid "Reason for slow down"
|
||||
msgstr "Raison de ralentir"
|
||||
|
||||
#: libretranslate/locales/.swag.py:28
|
||||
msgid "Translated file url"
|
||||
msgstr "Fichier traduit url"
|
||||
|
||||
#: libretranslate/locales/.swag.py:29
|
||||
msgid "Confidence value"
|
||||
msgstr "Valeur de confiance"
|
||||
|
||||
#: libretranslate/locales/.swag.py:30
|
||||
msgid "Character input limit for this language (-1 indicates no limit)"
|
||||
msgstr ""
|
||||
"Limite d'entrée de caractères pour cette langue (-1 n'indique aucune limite)"
|
||||
|
||||
#: libretranslate/locales/.swag.py:31
|
||||
msgid "Frontend translation timeout"
|
||||
msgstr "Délai de traduction de Frontend"
|
||||
|
||||
#: libretranslate/locales/.swag.py:32
|
||||
msgid "Whether the API key database is enabled."
|
||||
msgstr "Que la base de données clé API soit activée."
|
||||
|
||||
#: libretranslate/locales/.swag.py:33
|
||||
msgid "Whether an API key is required."
|
||||
msgstr "Si une clé API est requise."
|
||||
|
||||
#: libretranslate/locales/.swag.py:34
|
||||
msgid "Whether submitting suggestions is enabled."
|
||||
msgstr "La possibilité de soumettre des suggestions est activée."
|
||||
|
||||
#: libretranslate/locales/.swag.py:35
|
||||
msgid "Supported files format"
|
||||
msgstr "Format des fichiers supportés"
|
||||
|
||||
#: libretranslate/locales/.swag.py:36
|
||||
msgid "Whether submission was successful"
|
||||
msgstr "Que la soumission soit réussie"
|
||||
|
||||
#: libretranslate/templates/app.js.template:31
|
||||
#: libretranslate/templates/app.js.template:275
|
||||
#: libretranslate/templates/app.js.template:279
|
||||
msgid "Copy text"
|
||||
msgstr "Copie du texte"
|
||||
|
||||
#: libretranslate/templates/app.js.template:72
|
||||
#: libretranslate/templates/app.js.template:78
|
||||
#: libretranslate/templates/app.js.template:83
|
||||
#: libretranslate/templates/app.js.template:262
|
||||
#: libretranslate/templates/app.js.template:332
|
||||
#: libretranslate/templates/app.js.template:402
|
||||
#: libretranslate/templates/app.js.template:447
|
||||
#, python-format
|
||||
msgid "Cannot load %(url)s"
|
||||
msgstr "Charge %(url)s"
|
||||
|
||||
#: libretranslate/templates/app.js.template:253
|
||||
#: libretranslate/templates/app.js.template:323
|
||||
#: libretranslate/templates/app.js.template:385
|
||||
#: libretranslate/templates/app.js.template:395
|
||||
msgid "Unknown error"
|
||||
msgstr "Erreur inconnue"
|
||||
|
||||
#: libretranslate/templates/app.js.template:276
|
||||
msgid "Copied"
|
||||
msgstr "Copied"
|
||||
|
||||
#: libretranslate/templates/app.js.template:320
|
||||
msgid ""
|
||||
"Thanks for your correction. Note the suggestion will not take effect right "
|
||||
"away."
|
||||
msgstr ""
|
||||
"Merci pour votre correction. Notez que la suggestion ne prendra pas effet "
|
||||
"immédiatement."
|
||||
|
||||
#: libretranslate/templates/app.js.template:423
|
||||
msgid "No languages available. Did you install the models correctly?"
|
||||
msgstr ""
|
||||
"Pas de langues disponibles. Avez-vous installé les modèles correctement ?"
|
||||
|
||||
#: libretranslate/templates/app.js.template:479
|
||||
#, python-format
|
||||
msgid "Type in your API Key. If you need an API key, %(instructions)s"
|
||||
msgstr ""
|
||||
"Entrez votre clé API. Si vous avez besoin d'une clé API, %(instructions)s"
|
||||
|
||||
#: libretranslate/templates/app.js.template:479
|
||||
msgid "press the \"Get API Key\" link."
|
||||
msgstr "appuyez sur le lien \"Get API Key\"."
|
||||
|
||||
#: libretranslate/templates/app.js.template:479
|
||||
msgid "contact the server operator."
|
||||
msgstr "contactez l'opérateur du serveur."
|
||||
|
||||
#: libretranslate/templates/index.html:8
|
||||
#: libretranslate/templates/index.html:25
|
||||
#: libretranslate/templates/index.html:333
|
||||
msgid "Free and Open Source Machine Translation API"
|
||||
msgstr "API de Traduction Automatique gratuite et Open Source"
|
||||
|
||||
#: libretranslate/templates/index.html:10
|
||||
#: libretranslate/templates/index.html:29
|
||||
msgid ""
|
||||
"Free and Open Source Machine Translation API. Self-hosted, offline capable "
|
||||
"and easy to setup. Run your own API server in just a few minutes."
|
||||
msgstr ""
|
||||
"API de Traduction Automatique et Open Source. Auto-hostée, hors ligne "
|
||||
"capable et facile à installer. Exécutez votre propre serveur API en quelques"
|
||||
" minutes."
|
||||
|
||||
#: libretranslate/templates/index.html:11
|
||||
msgid "translation"
|
||||
msgstr "traduction"
|
||||
|
||||
#: libretranslate/templates/index.html:11
|
||||
msgid "api"
|
||||
msgstr "api"
|
||||
|
||||
#: libretranslate/templates/index.html:64
|
||||
msgid "API Docs"
|
||||
msgstr "API Docs"
|
||||
|
||||
#: libretranslate/templates/index.html:66
|
||||
msgid "Get API Key"
|
||||
msgstr "Obtenir API Key"
|
||||
|
||||
#: libretranslate/templates/index.html:68
|
||||
msgid "GitHub"
|
||||
msgstr "GitHub"
|
||||
|
||||
#: libretranslate/templates/index.html:70
|
||||
msgid "Set API Key"
|
||||
msgstr "Set API Key"
|
||||
|
||||
#: libretranslate/templates/index.html:72
|
||||
msgid "Change language"
|
||||
msgstr "Changer de langue"
|
||||
|
||||
#: libretranslate/templates/index.html:78
|
||||
msgid "Edit"
|
||||
msgstr "Edit"
|
||||
|
||||
#: libretranslate/templates/index.html:154
|
||||
msgid "Dismiss"
|
||||
msgstr "Dismiss"
|
||||
|
||||
#: libretranslate/templates/index.html:168
|
||||
msgid "Translation API"
|
||||
msgstr "API de traduction"
|
||||
|
||||
#: libretranslate/templates/index.html:172
|
||||
msgid "Translate Text"
|
||||
msgstr "Texte traduit"
|
||||
|
||||
#: libretranslate/templates/index.html:176
|
||||
msgid "Translate Files"
|
||||
msgstr "Translate Files"
|
||||
|
||||
#: libretranslate/templates/index.html:182
|
||||
msgid "Translate from"
|
||||
msgstr "Translate from"
|
||||
|
||||
#: libretranslate/templates/index.html:192
|
||||
msgid "Swap source and target languages"
|
||||
msgstr "Inverser la source et les langues cibles"
|
||||
|
||||
#: libretranslate/templates/index.html:195
|
||||
msgid "Translate into"
|
||||
msgstr "Translate into"
|
||||
|
||||
#: libretranslate/templates/index.html:207
|
||||
msgid "Text to translate"
|
||||
msgstr "Texte pour traduire"
|
||||
|
||||
#: libretranslate/templates/index.html:210
|
||||
msgid "Delete text"
|
||||
msgstr "Supprimer le texte"
|
||||
|
||||
#: libretranslate/templates/index.html:223
|
||||
msgid "Suggest translation"
|
||||
msgstr "Traduction suggérée"
|
||||
|
||||
#: libretranslate/templates/index.html:227
|
||||
msgid "Cancel"
|
||||
msgstr "Annuler"
|
||||
|
||||
#: libretranslate/templates/index.html:230
|
||||
msgid "Send"
|
||||
msgstr "Envoyer"
|
||||
|
||||
#: libretranslate/templates/index.html:246
|
||||
msgid "Supported file formats:"
|
||||
msgstr "Formats de fichiers supportés:"
|
||||
|
||||
#: libretranslate/templates/index.html:250
|
||||
msgid "File"
|
||||
msgstr "Fichier"
|
||||
|
||||
#: libretranslate/templates/index.html:265
|
||||
msgid "Remove file"
|
||||
msgstr "Supprimer le fichier"
|
||||
|
||||
#: libretranslate/templates/index.html:272
|
||||
msgid "Translate"
|
||||
msgstr "Traduire"
|
||||
|
||||
#: libretranslate/templates/index.html:273
|
||||
#: libretranslate/templates/index.html:317
|
||||
msgid "Download"
|
||||
msgstr "Télécharger"
|
||||
|
||||
#: libretranslate/templates/index.html:292
|
||||
msgid "Request"
|
||||
msgstr "Demande"
|
||||
|
||||
#: libretranslate/templates/index.html:297
|
||||
msgid "Response"
|
||||
msgstr "Réponse"
|
||||
|
||||
#: libretranslate/templates/index.html:312
|
||||
msgid "Open Source Machine Translation API"
|
||||
msgstr "Open Source API de Traduction automatique"
|
||||
|
||||
#: libretranslate/templates/index.html:313
|
||||
msgid "Self-Hosted. Offline Capable. Easy to Setup."
|
||||
msgstr "Auto-Hosted. Offline Capable. Facile à installer."
|
||||
|
||||
#: libretranslate/templates/index.html:332
|
||||
msgid "LibreTranslate"
|
||||
msgstr "LibreTranslate"
|
||||
|
||||
#: libretranslate/templates/index.html:334
|
||||
msgid "License:"
|
||||
msgstr "Licence:"
|
||||
|
||||
#: libretranslate/templates/index.html:337
|
||||
#, python-format
|
||||
msgid ""
|
||||
"This public API should be used for testing, personal or infrequent use. If "
|
||||
"you're going to run an application in production, please %(host_server)s or "
|
||||
"%(get_api_key)s."
|
||||
msgstr ""
|
||||
"Cette API publique devrait être utilisée pour les tests, l'utilisation "
|
||||
"personnelle ou occasionnelle. Si vous allez exécuter une demande en "
|
||||
"production, s'il vous plaît %(host_server)s ou %(get_api_key)s."
|
||||
|
||||
#: libretranslate/templates/index.html:337
|
||||
msgid "host your own server"
|
||||
msgstr "hôte de votre propre serveur"
|
||||
|
||||
#: libretranslate/templates/index.html:337
|
||||
msgid "get an API key"
|
||||
msgstr "obtenir une clé API"
|
||||
|
||||
#: libretranslate/templates/index.html:345
|
||||
#, python-format
|
||||
msgid "Made with %(heart)s by %(contributors)s and powered by %(engine)s"
|
||||
msgstr ""
|
||||
"Fabriqué avec %(heart)s by %(contributors)s et alimenté par %(engine)s"
|
||||
|
||||
#: libretranslate/templates/index.html:345
|
||||
#, python-format
|
||||
msgid "%(libretranslate)s Contributors"
|
||||
msgstr "%(libretranslate)s Contributeurs"
|
4
libretranslate/locales/fr/meta.json
Normal file
4
libretranslate/locales/fr/meta.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "French",
|
||||
"reviewed": false
|
||||
}
|
606
libretranslate/locales/it/LC_MESSAGES/messages.po
Normal file
606
libretranslate/locales/it/LC_MESSAGES/messages.po
Normal file
@ -0,0 +1,606 @@
|
||||
# Italian translations for LibreTranslate.
|
||||
# Copyright (C) 2023 LibreTranslate Authors
|
||||
# This file is distributed under the same license as the LibreTranslate
|
||||
# project.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: LibreTranslate 1.3.9\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2023-01-06 14:26-0500\n"
|
||||
"PO-Revision-Date: 2023-01-06 14:26-0500\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: it <LL@li.org>\n"
|
||||
"Language: it\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"Generated-By: Babel 2.11.0\n"
|
||||
|
||||
#: libretranslate/app.py:60
|
||||
msgid "Invalid JSON format"
|
||||
msgstr "Formato JSON non valido"
|
||||
|
||||
#: libretranslate/app.py:128 libretranslate/templates/app.js.template:427
|
||||
msgid "Auto Detect"
|
||||
msgstr "Rilevamento automatico"
|
||||
|
||||
#: libretranslate/app.py:193
|
||||
msgid "Unauthorized"
|
||||
msgstr "Non autorizzato"
|
||||
|
||||
#: libretranslate/app.py:211
|
||||
msgid "Too many request limits violations"
|
||||
msgstr "Troppe richieste limitano le violazioni"
|
||||
|
||||
#: libretranslate/app.py:220
|
||||
msgid "Invalid API key"
|
||||
msgstr "Chiave API non valida"
|
||||
|
||||
#: libretranslate/app.py:227
|
||||
msgid "Please contact the server operator to get an API key"
|
||||
msgstr ""
|
||||
"Si prega di contattare l'operatore del server per ottenere una chiave API"
|
||||
|
||||
#: libretranslate/app.py:229
|
||||
#, python-format
|
||||
msgid "Visit %(url)s to get an API key"
|
||||
msgstr "Visita %(url)s per ottenere una chiave API"
|
||||
|
||||
#: libretranslate/app.py:269
|
||||
msgid "Slowdown:"
|
||||
msgstr "Rallenta:"
|
||||
|
||||
#: libretranslate/app.py:467 libretranslate/app.py:469
|
||||
#: libretranslate/app.py:471 libretranslate/app.py:683
|
||||
#: libretranslate/app.py:685 libretranslate/app.py:687
|
||||
#: libretranslate/app.py:838 libretranslate/app.py:987
|
||||
#: libretranslate/app.py:989 libretranslate/app.py:991
|
||||
#: libretranslate/app.py:993
|
||||
#, python-format
|
||||
msgid "Invalid request: missing %(name)s parameter"
|
||||
msgstr "Richiesta non valida: mancante %(name)s parametro"
|
||||
|
||||
#: libretranslate/app.py:480 libretranslate/app.py:492
|
||||
#, python-format
|
||||
msgid "Invalid request: request (%(size)s) exceeds text limit (%(limit)s)"
|
||||
msgstr ""
|
||||
"Richiesta non valida: richiesta (%(size)s) supera il limite di testo "
|
||||
"(%(limit)s)"
|
||||
|
||||
#: libretranslate/app.py:525 libretranslate/app.py:530
|
||||
#: libretranslate/app.py:700 libretranslate/app.py:705
|
||||
#, python-format
|
||||
msgid "%(lang)s is not supported"
|
||||
msgstr "%(lang)s non è supportato"
|
||||
|
||||
#: libretranslate/app.py:536
|
||||
#, python-format
|
||||
msgid "%(format)s format is not supported"
|
||||
msgstr "%(format)s formato non è supportato"
|
||||
|
||||
#: libretranslate/app.py:544 libretranslate/app.py:568
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(tname)s (%(tcode)s) is not available as a target language from %(sname)s "
|
||||
"(%(scode)s)"
|
||||
msgstr ""
|
||||
"%(tname)s (%(tcode)s) non è disponibile come lingua di destinazione "
|
||||
"%(sname)s (%(scode)s)"
|
||||
|
||||
#: libretranslate/app.py:589
|
||||
#, python-format
|
||||
msgid "Cannot translate text: %(text)s"
|
||||
msgstr "Non può tradurre il testo: %(text)s"
|
||||
|
||||
#: libretranslate/app.py:676 libretranslate/app.py:730
|
||||
msgid "Files translation are disabled on this server."
|
||||
msgstr "La traduzione dei file è disabilitata su questo server."
|
||||
|
||||
#: libretranslate/app.py:690
|
||||
msgid "Invalid request: empty file"
|
||||
msgstr "Richiesta non valida: file vuoto"
|
||||
|
||||
#: libretranslate/app.py:693
|
||||
msgid "Invalid request: file format not supported"
|
||||
msgstr "Richiesta non valida: formato file non supportato"
|
||||
|
||||
#: libretranslate/app.py:738
|
||||
msgid "Invalid filename"
|
||||
msgstr "Invalid filename"
|
||||
|
||||
#: libretranslate/app.py:979
|
||||
msgid "Suggestions are disabled on this server."
|
||||
msgstr "I suggerimenti sono disabilitati su questo server."
|
||||
|
||||
#: libretranslate/locales/.langs.py:1
|
||||
msgid "English"
|
||||
msgstr "Inglese"
|
||||
|
||||
#: libretranslate/locales/.langs.py:2
|
||||
msgid "Arabic"
|
||||
msgstr "Arabo"
|
||||
|
||||
#: libretranslate/locales/.langs.py:3
|
||||
msgid "Azerbaijani"
|
||||
msgstr "Azerbaigian"
|
||||
|
||||
#: libretranslate/locales/.langs.py:4
|
||||
msgid "Chinese"
|
||||
msgstr "Cinese"
|
||||
|
||||
#: libretranslate/locales/.langs.py:5
|
||||
msgid "Czech"
|
||||
msgstr "Ceco"
|
||||
|
||||
#: libretranslate/locales/.langs.py:6
|
||||
msgid "Danish"
|
||||
msgstr "Danese"
|
||||
|
||||
#: libretranslate/locales/.langs.py:7
|
||||
msgid "Dutch"
|
||||
msgstr "Paesi Bassi"
|
||||
|
||||
#: libretranslate/locales/.langs.py:8
|
||||
msgid "Esperanto"
|
||||
msgstr "Esperanto"
|
||||
|
||||
#: libretranslate/locales/.langs.py:9
|
||||
msgid "Finnish"
|
||||
msgstr "Finlandia"
|
||||
|
||||
#: libretranslate/locales/.langs.py:10
|
||||
msgid "French"
|
||||
msgstr "Francese"
|
||||
|
||||
#: libretranslate/locales/.langs.py:11
|
||||
msgid "German"
|
||||
msgstr "Germania"
|
||||
|
||||
#: libretranslate/locales/.langs.py:12
|
||||
msgid "Greek"
|
||||
msgstr "Greco"
|
||||
|
||||
#: libretranslate/locales/.langs.py:13
|
||||
msgid "Hebrew"
|
||||
msgstr "Ebraico"
|
||||
|
||||
#: libretranslate/locales/.langs.py:14
|
||||
msgid "Hindi"
|
||||
msgstr "Hindi"
|
||||
|
||||
#: libretranslate/locales/.langs.py:15
|
||||
msgid "Hungarian"
|
||||
msgstr "Ungherese"
|
||||
|
||||
#: libretranslate/locales/.langs.py:16
|
||||
msgid "Indonesian"
|
||||
msgstr "Indonesiano"
|
||||
|
||||
#: libretranslate/locales/.langs.py:17
|
||||
msgid "Irish"
|
||||
msgstr "Irlanda"
|
||||
|
||||
#: libretranslate/locales/.langs.py:18
|
||||
msgid "Italian"
|
||||
msgstr "Italiano"
|
||||
|
||||
#: libretranslate/locales/.langs.py:19
|
||||
msgid "Japanese"
|
||||
msgstr "Giappone"
|
||||
|
||||
#: libretranslate/locales/.langs.py:20
|
||||
msgid "Korean"
|
||||
msgstr "Coreano"
|
||||
|
||||
#: libretranslate/locales/.langs.py:21
|
||||
msgid "Persian"
|
||||
msgstr "Persiano"
|
||||
|
||||
#: libretranslate/locales/.langs.py:22
|
||||
msgid "Polish"
|
||||
msgstr "Polacco"
|
||||
|
||||
#: libretranslate/locales/.langs.py:23
|
||||
msgid "Portuguese"
|
||||
msgstr "Portoghese"
|
||||
|
||||
#: libretranslate/locales/.langs.py:24
|
||||
msgid "Russian"
|
||||
msgstr "Russo"
|
||||
|
||||
#: libretranslate/locales/.langs.py:25
|
||||
msgid "Slovak"
|
||||
msgstr "Slovacchia"
|
||||
|
||||
#: libretranslate/locales/.langs.py:26
|
||||
msgid "Spanish"
|
||||
msgstr "Spagnolo"
|
||||
|
||||
#: libretranslate/locales/.langs.py:27
|
||||
msgid "Swedish"
|
||||
msgstr "Svezia"
|
||||
|
||||
#: libretranslate/locales/.langs.py:28
|
||||
msgid "Turkish"
|
||||
msgstr "Turco"
|
||||
|
||||
#: libretranslate/locales/.langs.py:29
|
||||
msgid "Ukranian"
|
||||
msgstr "Ucraina"
|
||||
|
||||
#: libretranslate/locales/.langs.py:30
|
||||
msgid "Vietnamese"
|
||||
msgstr "Vietnamita"
|
||||
|
||||
#: libretranslate/locales/.swag.py:1
|
||||
msgid "Retrieve list of supported languages"
|
||||
msgstr "Recuperare l'elenco delle lingue supportate"
|
||||
|
||||
#: libretranslate/locales/.swag.py:2
|
||||
msgid "List of languages"
|
||||
msgstr "Elenco delle lingue"
|
||||
|
||||
#: libretranslate/locales/.swag.py:3
|
||||
msgid "translate"
|
||||
msgstr "tradurre"
|
||||
|
||||
#: libretranslate/locales/.swag.py:4
|
||||
msgid "Translate text from a language to another"
|
||||
msgstr "Tradurre testo da una lingua a un'altra"
|
||||
|
||||
#: libretranslate/locales/.swag.py:5 libretranslate/templates/index.html:219
|
||||
msgid "Translated text"
|
||||
msgstr "Tradotto testo"
|
||||
|
||||
#: libretranslate/locales/.swag.py:6
|
||||
msgid "Invalid request"
|
||||
msgstr "Richiesta non valida"
|
||||
|
||||
#: libretranslate/locales/.swag.py:7
|
||||
msgid "Translation error"
|
||||
msgstr "Errore di traduzione"
|
||||
|
||||
#: libretranslate/locales/.swag.py:8
|
||||
msgid "Slow down"
|
||||
msgstr "Rallenta"
|
||||
|
||||
#: libretranslate/locales/.swag.py:9
|
||||
msgid "Banned"
|
||||
msgstr "Banati"
|
||||
|
||||
#: libretranslate/locales/.swag.py:10
|
||||
msgid "Translate file from a language to another"
|
||||
msgstr "Tradurre file da una lingua a un'altra"
|
||||
|
||||
#: libretranslate/locales/.swag.py:11
|
||||
msgid "Translated file"
|
||||
msgstr "Tradotto file"
|
||||
|
||||
#: libretranslate/locales/.swag.py:12
|
||||
msgid "Detect the language of a single text"
|
||||
msgstr "Rileva la lingua di un singolo testo"
|
||||
|
||||
#: libretranslate/locales/.swag.py:13
|
||||
msgid "Detections"
|
||||
msgstr "Rilevazioni"
|
||||
|
||||
#: libretranslate/locales/.swag.py:14
|
||||
msgid "Detection error"
|
||||
msgstr "Errore di rilevamento"
|
||||
|
||||
#: libretranslate/locales/.swag.py:15
|
||||
msgid "Retrieve frontend specific settings"
|
||||
msgstr "Recuperare le impostazioni specifiche di frontend"
|
||||
|
||||
#: libretranslate/locales/.swag.py:16
|
||||
msgid "frontend settings"
|
||||
msgstr "impostazioni di frontend"
|
||||
|
||||
#: libretranslate/locales/.swag.py:17
|
||||
msgid "frontend"
|
||||
msgstr "fronte"
|
||||
|
||||
#: libretranslate/locales/.swag.py:18
|
||||
msgid "Submit a suggestion to improve a translation"
|
||||
msgstr "Inviare un suggerimento per migliorare una traduzione"
|
||||
|
||||
#: libretranslate/locales/.swag.py:19
|
||||
msgid "Success"
|
||||
msgstr "Successo"
|
||||
|
||||
#: libretranslate/locales/.swag.py:20
|
||||
msgid "Not authorized"
|
||||
msgstr "Non autorizzato"
|
||||
|
||||
#: libretranslate/locales/.swag.py:21
|
||||
msgid "feedback"
|
||||
msgstr "feedback"
|
||||
|
||||
#: libretranslate/locales/.swag.py:22
|
||||
msgid "Language code"
|
||||
msgstr "Codice linguistico"
|
||||
|
||||
#: libretranslate/locales/.swag.py:23
|
||||
msgid "Human-readable language name (in English)"
|
||||
msgstr "Nome di lingua leggibile dall'uomo (in inglese)"
|
||||
|
||||
#: libretranslate/locales/.swag.py:24
|
||||
msgid "Supported target language codes"
|
||||
msgstr "Codici di lingua target supportati"
|
||||
|
||||
#: libretranslate/locales/.swag.py:25
|
||||
msgid "Translated text(s)"
|
||||
msgstr "Tradotto testo(i)"
|
||||
|
||||
#: libretranslate/locales/.swag.py:26
|
||||
msgid "Error message"
|
||||
msgstr "Messaggio di errore"
|
||||
|
||||
#: libretranslate/locales/.swag.py:27
|
||||
msgid "Reason for slow down"
|
||||
msgstr "Ragione per rallentare"
|
||||
|
||||
#: libretranslate/locales/.swag.py:28
|
||||
msgid "Translated file url"
|
||||
msgstr "Tradotto file url"
|
||||
|
||||
#: libretranslate/locales/.swag.py:29
|
||||
msgid "Confidence value"
|
||||
msgstr "Valore di fiducia"
|
||||
|
||||
#: libretranslate/locales/.swag.py:30
|
||||
msgid "Character input limit for this language (-1 indicates no limit)"
|
||||
msgstr "Limite di ingresso per questa lingua (-1 non indica limiti)"
|
||||
|
||||
#: libretranslate/locales/.swag.py:31
|
||||
msgid "Frontend translation timeout"
|
||||
msgstr "Tempo di traduzione Frontend"
|
||||
|
||||
#: libretranslate/locales/.swag.py:32
|
||||
msgid "Whether the API key database is enabled."
|
||||
msgstr "Se il database chiave API è abilitato."
|
||||
|
||||
#: libretranslate/locales/.swag.py:33
|
||||
msgid "Whether an API key is required."
|
||||
msgstr "Se è richiesta una chiave API."
|
||||
|
||||
#: libretranslate/locales/.swag.py:34
|
||||
msgid "Whether submitting suggestions is enabled."
|
||||
msgstr "Se presentare suggerimenti è abilitato."
|
||||
|
||||
#: libretranslate/locales/.swag.py:35
|
||||
msgid "Supported files format"
|
||||
msgstr "Formato file supportato"
|
||||
|
||||
#: libretranslate/locales/.swag.py:36
|
||||
msgid "Whether submission was successful"
|
||||
msgstr "Se la presentazione è stata di successo"
|
||||
|
||||
#: libretranslate/templates/app.js.template:31
|
||||
#: libretranslate/templates/app.js.template:275
|
||||
#: libretranslate/templates/app.js.template:279
|
||||
msgid "Copy text"
|
||||
msgstr "Copia testo"
|
||||
|
||||
#: libretranslate/templates/app.js.template:72
|
||||
#: libretranslate/templates/app.js.template:78
|
||||
#: libretranslate/templates/app.js.template:83
|
||||
#: libretranslate/templates/app.js.template:262
|
||||
#: libretranslate/templates/app.js.template:332
|
||||
#: libretranslate/templates/app.js.template:402
|
||||
#: libretranslate/templates/app.js.template:447
|
||||
#, python-format
|
||||
msgid "Cannot load %(url)s"
|
||||
msgstr "Non riesco a caricare %(url)s"
|
||||
|
||||
#: libretranslate/templates/app.js.template:253
|
||||
#: libretranslate/templates/app.js.template:323
|
||||
#: libretranslate/templates/app.js.template:385
|
||||
#: libretranslate/templates/app.js.template:395
|
||||
msgid "Unknown error"
|
||||
msgstr "Errore sconosciuto"
|
||||
|
||||
#: libretranslate/templates/app.js.template:276
|
||||
msgid "Copied"
|
||||
msgstr "Copie"
|
||||
|
||||
#: libretranslate/templates/app.js.template:320
|
||||
msgid ""
|
||||
"Thanks for your correction. Note the suggestion will not take effect right "
|
||||
"away."
|
||||
msgstr ""
|
||||
"Grazie per la sua correzione. Si noti che il suggerimento non avrà effetto "
|
||||
"subito."
|
||||
|
||||
#: libretranslate/templates/app.js.template:423
|
||||
msgid "No languages available. Did you install the models correctly?"
|
||||
msgstr "Nessuna lingua disponibile. Hai installato correttamente i modelli?"
|
||||
|
||||
#: libretranslate/templates/app.js.template:479
|
||||
#, python-format
|
||||
msgid "Type in your API Key. If you need an API key, %(instructions)s"
|
||||
msgstr ""
|
||||
"Digitare nella chiave API. Se hai bisogno di una chiave API, "
|
||||
"%(instructions)s"
|
||||
|
||||
#: libretranslate/templates/app.js.template:479
|
||||
msgid "press the \"Get API Key\" link."
|
||||
msgstr "premere il link \"Get API Key\"."
|
||||
|
||||
#: libretranslate/templates/app.js.template:479
|
||||
msgid "contact the server operator."
|
||||
msgstr "contattare l'operatore del server."
|
||||
|
||||
#: libretranslate/templates/index.html:8
|
||||
#: libretranslate/templates/index.html:25
|
||||
#: libretranslate/templates/index.html:333
|
||||
msgid "Free and Open Source Machine Translation API"
|
||||
msgstr "API di traduzione automatica gratuita e open source"
|
||||
|
||||
#: libretranslate/templates/index.html:10
|
||||
#: libretranslate/templates/index.html:29
|
||||
msgid ""
|
||||
"Free and Open Source Machine Translation API. Self-hosted, offline capable "
|
||||
"and easy to setup. Run your own API server in just a few minutes."
|
||||
msgstr ""
|
||||
"API di traduzione automatica gratuita e open source. Auto-hosted, offline in"
|
||||
" grado e facile da configurare. Eseguire il proprio server API in pochi "
|
||||
"minuti."
|
||||
|
||||
#: libretranslate/templates/index.html:11
|
||||
msgid "translation"
|
||||
msgstr "traduzione"
|
||||
|
||||
#: libretranslate/templates/index.html:11
|
||||
msgid "api"
|
||||
msgstr "api"
|
||||
|
||||
#: libretranslate/templates/index.html:64
|
||||
msgid "API Docs"
|
||||
msgstr "API"
|
||||
|
||||
#: libretranslate/templates/index.html:66
|
||||
msgid "Get API Key"
|
||||
msgstr "Ottieni API Chiave"
|
||||
|
||||
#: libretranslate/templates/index.html:68
|
||||
msgid "GitHub"
|
||||
msgstr "GitHub"
|
||||
|
||||
#: libretranslate/templates/index.html:70
|
||||
msgid "Set API Key"
|
||||
msgstr "Set API Chiave"
|
||||
|
||||
#: libretranslate/templates/index.html:72
|
||||
msgid "Change language"
|
||||
msgstr "Cambia la lingua"
|
||||
|
||||
#: libretranslate/templates/index.html:78
|
||||
msgid "Edit"
|
||||
msgstr "Modifica"
|
||||
|
||||
#: libretranslate/templates/index.html:154
|
||||
msgid "Dismiss"
|
||||
msgstr "Oggetto"
|
||||
|
||||
#: libretranslate/templates/index.html:168
|
||||
msgid "Translation API"
|
||||
msgstr "API di traduzione"
|
||||
|
||||
#: libretranslate/templates/index.html:172
|
||||
msgid "Translate Text"
|
||||
msgstr "Traduzione"
|
||||
|
||||
#: libretranslate/templates/index.html:176
|
||||
msgid "Translate Files"
|
||||
msgstr "Traduci file"
|
||||
|
||||
#: libretranslate/templates/index.html:182
|
||||
msgid "Translate from"
|
||||
msgstr "Traduttore da"
|
||||
|
||||
#: libretranslate/templates/index.html:192
|
||||
msgid "Swap source and target languages"
|
||||
msgstr "Swap sorgente e lingue di destinazione"
|
||||
|
||||
#: libretranslate/templates/index.html:195
|
||||
msgid "Translate into"
|
||||
msgstr "Traduzione"
|
||||
|
||||
#: libretranslate/templates/index.html:207
|
||||
msgid "Text to translate"
|
||||
msgstr "Testo da tradurre"
|
||||
|
||||
#: libretranslate/templates/index.html:210
|
||||
msgid "Delete text"
|
||||
msgstr "Eliminare il testo"
|
||||
|
||||
#: libretranslate/templates/index.html:223
|
||||
msgid "Suggest translation"
|
||||
msgstr "Suggerisci la traduzione"
|
||||
|
||||
#: libretranslate/templates/index.html:227
|
||||
msgid "Cancel"
|
||||
msgstr "Annulla"
|
||||
|
||||
#: libretranslate/templates/index.html:230
|
||||
msgid "Send"
|
||||
msgstr "Invia"
|
||||
|
||||
#: libretranslate/templates/index.html:246
|
||||
msgid "Supported file formats:"
|
||||
msgstr "Formati di file supportati:"
|
||||
|
||||
#: libretranslate/templates/index.html:250
|
||||
msgid "File"
|
||||
msgstr "File"
|
||||
|
||||
#: libretranslate/templates/index.html:265
|
||||
msgid "Remove file"
|
||||
msgstr "Rimuovi file"
|
||||
|
||||
#: libretranslate/templates/index.html:272
|
||||
msgid "Translate"
|
||||
msgstr "Traduttore"
|
||||
|
||||
#: libretranslate/templates/index.html:273
|
||||
#: libretranslate/templates/index.html:317
|
||||
msgid "Download"
|
||||
msgstr "Scarica"
|
||||
|
||||
#: libretranslate/templates/index.html:292
|
||||
msgid "Request"
|
||||
msgstr "Richiesta"
|
||||
|
||||
#: libretranslate/templates/index.html:297
|
||||
msgid "Response"
|
||||
msgstr "Risposta"
|
||||
|
||||
#: libretranslate/templates/index.html:312
|
||||
msgid "Open Source Machine Translation API"
|
||||
msgstr "API di traduzione automatica Open Source"
|
||||
|
||||
#: libretranslate/templates/index.html:313
|
||||
msgid "Self-Hosted. Offline Capable. Easy to Setup."
|
||||
msgstr "Ossessionato. Offline Capable. Facile da configurare."
|
||||
|
||||
#: libretranslate/templates/index.html:332
|
||||
msgid "LibreTranslate"
|
||||
msgstr "LibreTranslate"
|
||||
|
||||
#: libretranslate/templates/index.html:334
|
||||
msgid "License:"
|
||||
msgstr "Licenza:"
|
||||
|
||||
#: libretranslate/templates/index.html:337
|
||||
#, python-format
|
||||
msgid ""
|
||||
"This public API should be used for testing, personal or infrequent use. If "
|
||||
"you're going to run an application in production, please %(host_server)s or "
|
||||
"%(get_api_key)s."
|
||||
msgstr ""
|
||||
"Questa API pubblica dovrebbe essere utilizzata per il test, uso personale o "
|
||||
"infrequente. Se hai intenzione di eseguire un'applicazione in produzione, "
|
||||
"per favore %(host_server)s o %(get_api_key)s."
|
||||
|
||||
#: libretranslate/templates/index.html:337
|
||||
msgid "host your own server"
|
||||
msgstr "host tuo server"
|
||||
|
||||
#: libretranslate/templates/index.html:337
|
||||
msgid "get an API key"
|
||||
msgstr "ottenere una chiave API"
|
||||
|
||||
#: libretranslate/templates/index.html:345
|
||||
#, python-format
|
||||
msgid "Made with %(heart)s by %(contributors)s and powered by %(engine)s"
|
||||
msgstr ""
|
||||
"Realizzato con %(heart)s di %(contributors)s e alimentato da %(engine)s"
|
||||
|
||||
#: libretranslate/templates/index.html:345
|
||||
#, python-format
|
||||
msgid "%(libretranslate)s Contributors"
|
||||
msgstr "%(libretranslate)s Contributori"
|
4
libretranslate/locales/it/meta.json
Normal file
4
libretranslate/locales/it/meta.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "Italian",
|
||||
"reviewed": false
|
||||
}
|
@ -52,7 +52,7 @@
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
select {
|
||||
select, select#locales{
|
||||
color: #fff;
|
||||
background: #111;
|
||||
}
|
||||
|
@ -11,6 +11,10 @@ a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a.noline{
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#app {
|
||||
min-height: 80vh;
|
||||
}
|
||||
@ -35,6 +39,88 @@ h3.header {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.top-nav .locale-panel{
|
||||
position: absolute;
|
||||
top: 64px;
|
||||
height: 68px;
|
||||
right: 0;
|
||||
padding: 0 16px;
|
||||
width: 240px;
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
box-shadow: 0 2px 2px 0 rgb(0 0 0 / 14%), 0 3px 1px -2px rgb(0 0 0 / 12%), 0px 4px 5px 0 rgb(0 0 0 / 20%);
|
||||
}
|
||||
|
||||
.locale-panel{
|
||||
display: none;
|
||||
}
|
||||
|
||||
#nav:hover .change-language:hover + .locale-panel,
|
||||
#nav-mobile:hover .change-language:hover + .locale-panel,
|
||||
.change-language.clicked + .locale-panel{
|
||||
display: block;
|
||||
}
|
||||
|
||||
#nav:hover .locale-panel:hover,
|
||||
#nav-mobile .locale-panel:hover{
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
.locale-panel select{
|
||||
display: block;
|
||||
height: 32px;
|
||||
font-size: 14px;
|
||||
background-color: #fff;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.locale-panel a{
|
||||
line-height: normal;
|
||||
font-size: 90%;
|
||||
padding: 0;
|
||||
margin-top: 6px;
|
||||
text-align: right;
|
||||
text-decoration: none;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.locale-panel a:hover{
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.locale-panel a i.material-icons{
|
||||
display: inline-block;
|
||||
line-height: initial;
|
||||
line-height: 14px;
|
||||
font-size: 100%;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
}
|
||||
|
||||
.locale-panel a:hover{
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
#nav-mobile .locale-panel{
|
||||
color: rgba(0,0,0,0.87);
|
||||
padding: 0 32px;
|
||||
padding-top: 12px;
|
||||
}
|
||||
|
||||
#nav-mobile a, #nav-mobile a i.material-icons{
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#nav-mobile .locale-panel a{
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#nav-mobile .locale-panel a i.material-icons{
|
||||
float: none;
|
||||
}
|
||||
|
||||
.language-select {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
@ -1,6 +1,6 @@
|
||||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
|
||||
// API host/endpoint
|
||||
var BaseUrl = window.location.protocol + "//" + window.location.host + url_prefix ;
|
||||
var BaseUrl = window.location.protocol + "//" + window.location.host + "{{ url_prefix }}" ;
|
||||
var htmlRegex = /<(.*)>.*?|<(.*)\/>/;
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
var sidenavElems = document.querySelectorAll('.sidenav');
|
||||
@ -28,7 +28,7 @@ document.addEventListener('DOMContentLoaded', function(){
|
||||
|
||||
detectedLangText: "",
|
||||
|
||||
copyTextLabel: "Copy text",
|
||||
copyTextLabel: {{ _e("Copy text") }},
|
||||
|
||||
suggestions: false,
|
||||
isSuggesting: false,
|
||||
@ -69,18 +69,18 @@ document.addEventListener('DOMContentLoaded', function(){
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.error = "Cannot load /frontend/settings";
|
||||
self.error = {{ _e("Cannot load %(url)s", url="/frontend/settings") }};
|
||||
self.loading = false;
|
||||
}
|
||||
};
|
||||
|
||||
settingsRequest.onerror = function() {
|
||||
self.error = "Error while calling /frontend/settings";
|
||||
self.error = {{ _e("Cannot load %(url)s", url="/frontend/settings") }};
|
||||
self.loading = false;
|
||||
};
|
||||
|
||||
langsRequest.onerror = function() {
|
||||
self.error = "Error while calling /languages";
|
||||
self.error = {{ _e("Cannot load %(url)s", url="/languages") }};
|
||||
self.loading = false;
|
||||
};
|
||||
|
||||
@ -250,7 +250,7 @@ document.addEventListener('DOMContentLoaded', function(){
|
||||
self.detectedLangText = ": " + (lang !== undefined ? lang.name : res.detectedLanguage.language) + " (" + res.detectedLanguage.confidence + "%)";
|
||||
}
|
||||
} else{
|
||||
throw new Error(res.error || "Unknown error");
|
||||
throw new Error(res.error || {{ _e("Unknown error") }});
|
||||
}
|
||||
} catch (e) {
|
||||
self.error = e.message;
|
||||
@ -259,7 +259,7 @@ document.addEventListener('DOMContentLoaded', function(){
|
||||
};
|
||||
|
||||
request.onerror = function() {
|
||||
self.error = "Error while calling /translate";
|
||||
self.error = {{ _e("Cannot load %(url)s", url="/translate") }};
|
||||
self.loadingTranslation = false;
|
||||
};
|
||||
|
||||
@ -272,11 +272,11 @@ document.addEventListener('DOMContentLoaded', function(){
|
||||
this.$refs.translatedTextarea.setSelectionRange(0, 9999999); /* For mobile devices */
|
||||
document.execCommand("copy");
|
||||
|
||||
if (this.copyTextLabel === "Copy text"){
|
||||
this.copyTextLabel = "Copied";
|
||||
if (this.copyTextLabel === {{ _e("Copy text") }}){
|
||||
this.copyTextLabel = {{ _e("Copied") }};
|
||||
var self = this;
|
||||
setTimeout(function(){
|
||||
self.copyTextLabel = "Copy text";
|
||||
self.copyTextLabel = {{ _e("Copy text") }};
|
||||
}, 1500);
|
||||
}
|
||||
},
|
||||
@ -317,10 +317,10 @@ document.addEventListener('DOMContentLoaded', function(){
|
||||
try{
|
||||
var res = JSON.parse(this.response);
|
||||
if (res.success){
|
||||
M.toast({html: 'Thanks for your correction. Note the suggestion will not take effect right away.'})
|
||||
M.toast({html: {{ _e("Thanks for your correction. Note the suggestion will not take effect right away.") }} })
|
||||
self.closeSuggestTranslation(e)
|
||||
}else{
|
||||
throw new Error(res.error || "Unknown error");
|
||||
throw new Error(res.error || {{ _e("Unknown error") }});
|
||||
}
|
||||
}catch(e){
|
||||
self.error = e.message;
|
||||
@ -329,7 +329,7 @@ document.addEventListener('DOMContentLoaded', function(){
|
||||
};
|
||||
|
||||
request.onerror = function() {
|
||||
self.error = "Error while calling /suggest";
|
||||
self.error = {{ _e("Cannot load %(url)s", url="/suggest") }};
|
||||
self.loadingTranslation = false;
|
||||
};
|
||||
|
||||
@ -382,7 +382,7 @@ document.addEventListener('DOMContentLoaded', function(){
|
||||
link.href = self.translatedFileUrl;
|
||||
link.click();
|
||||
}else{
|
||||
throw new Error(res.error || "Unknown error");
|
||||
throw new Error(res.error || {{ _e("Unknown error") }});
|
||||
}
|
||||
|
||||
}catch(e){
|
||||
@ -392,14 +392,14 @@ document.addEventListener('DOMContentLoaded', function(){
|
||||
}
|
||||
}else{
|
||||
let res = JSON.parse(this.response);
|
||||
self.error = res.error || "Unknown error";
|
||||
self.error = res.error || {{ _e("Unknown error") }};
|
||||
self.loadingFileTranslation = false;
|
||||
self.inputFile = false;
|
||||
}
|
||||
}
|
||||
|
||||
translateFileRequest.onerror = function() {
|
||||
self.error = "Error while calling /translate_file";
|
||||
self.error = {{ _e("Cannot load %(url)s", url="/translate_file") }};
|
||||
self.loadingFileTranslation = false;
|
||||
self.inputFile = false;
|
||||
};
|
||||
@ -420,11 +420,11 @@ function handleLangsResponse(self, response) {
|
||||
|
||||
if (self.langs.length === 0){
|
||||
self.loading = false;
|
||||
self.error = "No languages available. Did you install the models correctly?"
|
||||
self.error = {{ _e("No languages available. Did you install the models correctly?") }};
|
||||
return;
|
||||
}
|
||||
|
||||
self.langs.push({ name: "Auto Detect", code: "auto", targets: self.langs.map(l => l.code)})
|
||||
self.langs.push({ name: {{ _e("Auto Detect") }}, code: "auto", targets: self.langs.map(l => l.code)})
|
||||
|
||||
const sourceLanguage = self.langs.find(l => l.code === self.getQueryParam("source"))
|
||||
const targetLanguage = self.langs.find(l => l.code === self.getQueryParam("target"))
|
||||
@ -444,7 +444,7 @@ function handleLangsResponse(self, response) {
|
||||
self.handleInput(new Event('none'))
|
||||
}
|
||||
} else {
|
||||
self.error = "Cannot load /languages";
|
||||
self.error = {{ _e("Cannot load %(url)s", url="/languages") }};
|
||||
}
|
||||
|
||||
self.loading = false;
|
||||
@ -476,9 +476,7 @@ function getTextWidth(text) {
|
||||
function setApiKey(){
|
||||
var prevKey = localStorage.getItem("api_key") || "";
|
||||
var newKey = "";
|
||||
var instructions = "contact the server operator.";
|
||||
if (window.getApiKeyLink) instructions = "press the \"Get API Key\" link."
|
||||
newKey = window.prompt("Type in your API Key. If you need an API key, " + instructions, prevKey);
|
||||
newKey = window.prompt({{ _e("Type in your API Key. If you need an API key, %(instructions)s", instructions=_e("press the \"Get API Key\" link.") if get_api_key_link else _e("contact the server operator.")) }}, prevKey);
|
||||
if (newKey === null) newKey = "";
|
||||
|
||||
localStorage.setItem("api_key", newKey);
|
@ -1,21 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="{{ current_locale }}">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>LibreTranslate - Free and Open Source Machine Translation API</title>
|
||||
{% for al in alternate_locales %}<link rel="alternate" hreflang="{{ al.lang }}" href="{{ al.link }}" />
|
||||
{% endfor %}
|
||||
<title>LibreTranslate - {{ _h("Free and Open Source Machine Translation API") }}</title>
|
||||
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
||||
<meta name="description" content="Free and Open Source Machine Translation API. 100% self-hosted, offline capable and easy to setup. Run your own API server in just a few minutes.">
|
||||
<meta name="keywords" content="translation,api">
|
||||
<script type="text/javascript">
|
||||
var url_prefix = "{{ url_prefix }}"
|
||||
</script>
|
||||
<meta name="description" content="{{ _h('Free and Open Source Machine Translation API. Self-hosted, offline capable and easy to setup. Run your own API server in just a few minutes.') }}">
|
||||
<meta name="keywords" content="{{ _h('translation') }},{{ _h('api') }}">
|
||||
|
||||
<link rel="preload" href="{{ url_for('static', filename='icon.svg') }}" as="image" />
|
||||
<link rel="preload" href="{{ url_for('static', filename='js/vue@2.js') }}" as="script">
|
||||
<link rel="preload" href="{{ url_for('static', filename='js/materialize.min.js') }}" as="script">
|
||||
<link rel="preload" href="{{ url_for('static', filename='js/prism.min.js') }}" as="script">
|
||||
<link rel="preload" href="{{ url_for('static', filename='js/app.js') }}?v={{ version }}" as="script">
|
||||
<link rel="preload" href="js/app.js?v={{ version }}" as="script">
|
||||
|
||||
<link rel="preload" href="{{ url_for('static', filename='css/materialize.min.css') }}" as="style"/>
|
||||
<link rel="preload" href="{{ url_for('static', filename='css/material-icons.css') }}" as="style"/>
|
||||
@ -23,11 +22,11 @@
|
||||
<link rel="preload" href="{{ url_for('static', filename='css/main.css') }}?v={{ version }}" as="style"/>
|
||||
<link rel="preload" href="{{ url_for('static', filename='css/dark-theme.css') }}" as="style"/>
|
||||
|
||||
<meta property="og:title" content="LibreTranslate - Free and Open Source Machine Translation API" />
|
||||
<meta property="og:title" content="LibreTranslate - {{ _h('Free and Open Source Machine Translation API') }}" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://libretranslate.com" />
|
||||
<meta property="og:image" content="https://user-images.githubusercontent.com/1951843/102724116-32a6df00-42db-11eb-8cc0-129ab39cdfb5.png" />
|
||||
<meta property="og:description" name="description" class="swiftype" content="Free and Open Source Machine Translation API. 100% self-hosted, no limits, no ties to proprietary services. Run your own API server in just a few minutes."/>
|
||||
<meta property="og:description" name="description" class="swiftype" content="{{ _h('Free and Open Source Machine Translation API. Self-hosted, offline capable and easy to setup. Run your own API server in just a few minutes.') }}"/>
|
||||
|
||||
<script src="{{ url_for('static', filename='js/vue@2.js') }}"></script>
|
||||
|
||||
@ -60,28 +59,64 @@
|
||||
<img src="{{ url_for('static', filename='icon.svg') }}" alt="" class="logo">
|
||||
<span>LibreTranslate</span>
|
||||
</a>
|
||||
<ul class="right hide-on-med-and-down">
|
||||
<li><a href="{{ swagger_url }}">API Docs</a></li>
|
||||
{% if get_api_key_link %}
|
||||
<li><a href="{{ get_api_key_link }}">Get API Key</a></li>
|
||||
<script>window.getApiKeyLink = "{{ get_api_key_link }}";</script>
|
||||
{% endif %}
|
||||
<li><a href="https://github.com/LibreTranslate/LibreTranslate" rel="noopener noreferrer">GitHub</a></li>
|
||||
{% if api_keys %}
|
||||
<li><a href="javascript:setApiKey()" title="Set API Key" aria-label="Set API Key"><i class="material-icons">vpn_key</i></a></li>
|
||||
{% endif %}
|
||||
<ul id="nav" class="right hide-on-med-and-down top-nav position-relative">
|
||||
{% set menulinks %}
|
||||
<li><a href="{{ swagger_url }}">{{ _h("API Docs") }}</a></li>
|
||||
{% if get_api_key_link %}
|
||||
<li><a href="{{ get_api_key_link }}">{{ _h("Get API Key") }}</a></li>
|
||||
{% endif %}
|
||||
<li><a href="https://github.com/LibreTranslate/LibreTranslate" rel="noopener noreferrer">{{ _h("GitHub") }}</a></li>
|
||||
{% if api_keys %}
|
||||
<li><a class="noline" href="javascript:setApiKey()" title="{{ _h('Set API Key') }}" aria-label="{{ _h('Set API Key') }}"><i class="material-icons">vpn_key</i></a></li>
|
||||
{% endif %}
|
||||
<li class="change-language"><a class="noline" href="javascript:void(0)" title="{{ _h('Change language') }}"><i class="material-icons">language</i></a>
|
||||
</li>
|
||||
<li class="locale-panel blue darken-3">
|
||||
<select id="locales" onchange="changeLocale(this)">
|
||||
{% for l in available_locales %}<option value="{{ l['code'] }}" {{ 'selected' if current_locale == l['code'] else ''}}>{{ l['name'] }}</option>{% endfor %}
|
||||
</select>
|
||||
<a href="#TODO">{{ _h("Edit") }}<i class="material-icons">create</i></a>
|
||||
</li>
|
||||
{% endset %}
|
||||
{{ menulinks }}
|
||||
</ul>
|
||||
<ul id="nav-mobile" class="sidenav blue darken-3">
|
||||
{{ menulinks }}
|
||||
</ul>
|
||||
<script>
|
||||
var localeLinks = {
|
||||
{% for al in alternate_locales %}"{{ al.lang }}": "{{ al.link }}"{% if not loop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
<ul id="nav-mobile" class="sidenav">
|
||||
<li><a href="{{ swagger_url }}">API Docs</a></li>
|
||||
{% if get_api_key_link %}
|
||||
<li><a href="{{ get_api_key_link }}">Get API Key</a></li>
|
||||
{% endif %}
|
||||
<li><a href="https://github.com/LibreTranslate/LibreTranslate" rel="noopener noreferrer">GitHub</a></li>
|
||||
{% if api_keys %}
|
||||
<li><a href="javascript:setApiKey()" title="Set API Key" aria-label="Set API Key"><i class="material-icons">vpn_key</i></a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
function changeLocale(slt){
|
||||
var lang = slt.value;
|
||||
if (localeLinks[lang]) location.href = localeLinks[lang];
|
||||
else location.href = '?lang=' + slt.value;
|
||||
}
|
||||
|
||||
var btnChangeLangs = document.getElementsByClassName("change-language");
|
||||
var localePanels = document.getElementsByClassName("locale-panel");
|
||||
console.log(btnChangeLangs);
|
||||
for (var i = 0; i < btnChangeLangs.length; i++){
|
||||
(function(btn){
|
||||
btn.addEventListener('click', function(e){
|
||||
e.stopPropagation();
|
||||
btn.classList.toggle('clicked');
|
||||
});
|
||||
})(btnChangeLangs[i]);
|
||||
}
|
||||
for (var i = 0; i < localePanels.length; i++){
|
||||
localePanels[i].addEventListener('click', function(e){
|
||||
e.stopPropagation();
|
||||
});
|
||||
}
|
||||
document.addEventListener('click', function(){
|
||||
for (var i = 0; i < btnChangeLangs.length; i++){
|
||||
btnChangeLangs[i].classList.remove('clicked');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
@ -116,7 +151,7 @@
|
||||
<i class="material-icons">warning</i><p> [[ error ]]</p>
|
||||
</div>
|
||||
<div class="card-action">
|
||||
<a href="#" @click="dismissError">Dismiss</a>
|
||||
<a href="#" @click="dismissError">{{ _h("Dismiss") }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -130,22 +165,22 @@
|
||||
<div class="section no-pad-bot">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<h3 class="header center">Translation API</h3>
|
||||
<h3 class="header center">{{ _h("Translation API") }}</h3>
|
||||
<div id="translation-type-btns" class="s12 center" v-if="filesTranslation === true">
|
||||
<button type="button" class="btn btn-switch-type" @click="switchType('text')" :class="{'active': translationType === 'text'}">
|
||||
<i aria-hidden="true" class="material-icons">title</i>
|
||||
<span class="btn-text">Translate Text</span>
|
||||
<span class="btn-text">{{ _h("Translate Text") }}</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-switch-type" @click="switchType('files')" :class="{'active': translationType === 'files'}">
|
||||
<i aria-hidden="true" class="material-icons">description</i>
|
||||
<span class="btn-text">Translate Files</span>
|
||||
<span class="btn-text">{{ _h("Translate Files") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<form id="translation-form" class="col s12">
|
||||
<div class="row mb-0">
|
||||
<div class="col s6 language-select">
|
||||
<span id="sourceLangLabel">Translate from</span>
|
||||
<span v-if="detectedLangText !== ''">[[ detectedLangText ]]</span>
|
||||
<span id="sourceLangLabel">{{ _h("Translate from") }}</span>
|
||||
<span v-if="detectedLangText !== ''">[[ detectedLangText ]]</span>
|
||||
<select aria-labelledby="sourceLangLabel" class="browser-default" v-model="sourceLang" ref="sourceLangDropdown" @change="handleInput">
|
||||
<template v-for="option in langs">
|
||||
<option :value="option.code">[[ option.name ]]</option>
|
||||
@ -154,10 +189,10 @@
|
||||
</div>
|
||||
|
||||
<div class="col s6 language-select">
|
||||
<a href="javascript:void(0)" @click="swapLangs" class="btn-switch-language" aria-label="Swap source and target languages">
|
||||
<a href="javascript:void(0)" @click="swapLangs" class="btn-switch-language" aria-label="{{ _h('Swap source and target languages') }}">
|
||||
<i class="material-icons">swap_horiz</i>
|
||||
</a>
|
||||
<span id="targetLangLabel">Translate into</span>
|
||||
<span id="targetLangLabel">{{ _h("Translate into") }}</span>
|
||||
<select aria-labelledby="targetLangLabel" class="browser-default" v-model="targetLang" ref="targetLangDropdown" @change="handleInput">
|
||||
<template v-for="option in targetLangs">
|
||||
<option v-if="option.code !== 'auto'" :value="option.code">[[ option.name ]]</option>
|
||||
@ -169,10 +204,10 @@
|
||||
<div class="row" v-if="translationType === 'text'">
|
||||
<div class="input-field textarea-container col s6">
|
||||
<label for="textarea1" class="sr-only">
|
||||
Text to translate
|
||||
{{ _h("Text to translate") }}
|
||||
</label>
|
||||
<textarea id="textarea1" v-model="inputText" @input="handleInput" ref="inputTextarea" dir="auto"></textarea>
|
||||
<button class="btn-delete-text" title="Delete text" aria-label="Delete text" @click="deleteText">
|
||||
<button class="btn-delete-text" title="{{ _h('Delete text') }}" aria-label="{{ _h('Delete text') }}" aria-label="Delete text" @click="deleteText">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
<div class="characters-limit-container" v-if="charactersLimit !== -1">
|
||||
@ -181,23 +216,23 @@
|
||||
</div>
|
||||
<div class="input-field textarea-container col s6">
|
||||
<label for="textarea2" class="sr-only">
|
||||
Translated text
|
||||
{{ _h("Translated text") }}
|
||||
</label>
|
||||
<textarea id="textarea2" v-model="translatedText" ref="translatedTextarea" dir="auto" v-bind:readonly="suggestions && !isSuggesting"></textarea>
|
||||
<div class="actions">
|
||||
<button v-if="suggestions && !loadingTranslation && inputText.length && !isSuggesting" class="btn-action" @click="suggestTranslation" aria-label="Suggest translation">
|
||||
<i class="material-icons">edit</i>
|
||||
</button>
|
||||
<button v-if="suggestions && !loadingTranslation && inputText.length && isSuggesting" class="btn-action btn-blue" @click="closeSuggestTranslation">
|
||||
<span>Cancel</span>
|
||||
</button>
|
||||
<button v-if="suggestions && !loadingTranslation && inputText.length && isSuggesting" :disabled="!canSendSuggestion" class="btn-action btn-blue" @click="sendSuggestion">
|
||||
<span>Send</span>
|
||||
</button>
|
||||
<button v-if="!isSuggesting" class="btn-action btn-copy-translated" @click="copyText">
|
||||
<span>[[ copyTextLabel ]]</span> <i class="material-icons" aria-hidden="true">content_copy</i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button v-if="suggestions && !loadingTranslation && inputText.length && !isSuggesting" class="btn-action" @click="suggestTranslation" aria-label="{{ _h('Suggest translation') }}">
|
||||
<i class="material-icons">edit</i>
|
||||
</button>
|
||||
<button v-if="suggestions && !loadingTranslation && inputText.length && isSuggesting" class="btn-action btn-blue" @click="closeSuggestTranslation">
|
||||
<span>{{ _h("Cancel") }}</span>
|
||||
</button>
|
||||
<button v-if="suggestions && !loadingTranslation && inputText.length && isSuggesting" :disabled="!canSendSuggestion" class="btn-action btn-blue" @click="sendSuggestion">
|
||||
<span>{{ _h("Send") }}</span>
|
||||
</button>
|
||||
<button v-if="!isSuggesting" class="btn-action btn-copy-translated" @click="copyText">
|
||||
<span>[[ copyTextLabel ]]</span> <i class="material-icons" aria-hidden="true">content_copy</i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="position-relative">
|
||||
<div class="progress translate" v-if="loadingTranslation">
|
||||
<div class="indeterminate"></div>
|
||||
@ -205,43 +240,43 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" v-if="translationType === 'files'">
|
||||
<div class="file-dropzone">
|
||||
<div v-if="inputFile === false" class="dropzone-content">
|
||||
<span>Supported file formats: [[ supportedFilesFormatFormatted ]]</span>
|
||||
<form action="#">
|
||||
<div class="file-field input-field">
|
||||
<div class="btn">
|
||||
<span id="fileLabel">File</span>
|
||||
<input aria-labelledby="fileLabel" type="file" :accept="supportedFilesFormatFormatted" @change="handleInputFile" ref="fileInputRef">
|
||||
</div>
|
||||
<div class="file-path-wrapper hidden">
|
||||
<input class="file-path validate" type="text">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div v-if="inputFile !== false" class="dropzone-content">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<div class="row mb-0">
|
||||
<div class="col s12">
|
||||
[[ inputFile.name ]]
|
||||
<button v-if="loadingFileTranslation !== true" @click="removeFile" class="btn-flat" aria-label="Remove file">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button @click="translateFile" v-if="translatedFileUrl === false && loadingFileTranslation === false" class="btn">Translate</button>
|
||||
<a v-if="translatedFileUrl !== false" :href="translatedFileUrl" class="btn">Download</a>
|
||||
<div class="progress" v-if="loadingFileTranslation">
|
||||
<div class="indeterminate"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" v-if="translationType === 'files'">
|
||||
<div class="file-dropzone">
|
||||
<div v-if="inputFile === false" class="dropzone-content">
|
||||
<span>{{ _h("Supported file formats:") }} [[ supportedFilesFormatFormatted ]]</span>
|
||||
<form action="#">
|
||||
<div class="file-field input-field">
|
||||
<div class="btn">
|
||||
<span id="fileLabel">{{ _h("File") }}</span>
|
||||
<input aria-labelledby="fileLabel" type="file" :accept="supportedFilesFormatFormatted" @change="handleInputFile" ref="fileInputRef">
|
||||
</div>
|
||||
<div class="file-path-wrapper hidden">
|
||||
<input class="file-path validate" type="text">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div v-if="inputFile !== false" class="dropzone-content">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<div class="row mb-0">
|
||||
<div class="col s12">
|
||||
[[ inputFile.name ]]
|
||||
<button v-if="loadingFileTranslation !== true" @click="removeFile" class="btn-flat" aria-label="{{ _h('Remove file') }}">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button @click="translateFile" v-if="translatedFileUrl === false && loadingFileTranslation === false" class="btn">{{ _h("Translate") }}</button>
|
||||
<a v-if="translatedFileUrl !== false" :href="translatedFileUrl" class="btn">{{ _h("Download") }}</a>
|
||||
<div class="progress" v-if="loadingFileTranslation">
|
||||
<div class="indeterminate"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@ -254,12 +289,12 @@
|
||||
|
||||
<div class="row center">
|
||||
<div class="col s12 m12 l6 left-align">
|
||||
<p class="mb-0">Request</p>
|
||||
<p class="mb-0">{{ _h("Request") }}</p>
|
||||
<pre class="code mt-0"><code class="language-javascript" v-html="$options.filters.highlight(requestCode)">
|
||||
</code></pre>
|
||||
</div>
|
||||
<div class="col s12 m12 l6 left-align">
|
||||
<p class="mb-0">Response</p>
|
||||
<p class="mb-0">{{ _h("Response") }}</p>
|
||||
<pre class="code mt-0"><code class="language-javascript" v-html="$options.filters.highlight(output)">
|
||||
</code></pre>
|
||||
</div>
|
||||
@ -274,12 +309,12 @@
|
||||
<div class="container">
|
||||
<div class="row center">
|
||||
<div class="col s12 m12">
|
||||
<h3 class="header">Open Source Machine Translation API</h3>
|
||||
<h4 class="header">100% Self-Hosted. Offline Capable. Easy to Setup.</h4>
|
||||
<h3 class="header">{{ _h("Open Source Machine Translation API") }}</h3>
|
||||
<h4 class="header">{{ _h("Self-Hosted. Offline Capable. Easy to Setup.") }}</h4>
|
||||
<div id="download-btn-wrapper">
|
||||
<a id="download-btn" class="waves-effect waves-light btn btn-large teal darken-2" href="https://github.com/LibreTranslate/LibreTranslate" rel="noopener noreferrer">
|
||||
<i aria-hidden="true" class="material-icons">cloud_download</i>
|
||||
<span class="btn-text">Download</span>
|
||||
<span class="btn-text">{{ _h("Download") }}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@ -294,13 +329,12 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col l12 s12">
|
||||
<h5 class="white-text">LibreTranslate</h5>
|
||||
<p class="grey-text text-lighten-4">Free and Open Source Machine Translation API</p>
|
||||
<p>License: <a class="grey-text text-lighten-4" href="https://www.gnu.org/licenses/agpl-3.0.en.html" rel="noopener noreferrer">AGPLv3</a></p>
|
||||
<p><a class="grey-text text-lighten-4" href="/javascript-licenses" rel="jslicense">JavaScript license information</a></p>
|
||||
<h5 class="white-text">{{ _h("LibreTranslate") }}</h5>
|
||||
<p class="grey-text text-lighten-4">{{ _h("Free and Open Source Machine Translation API") }}</p>
|
||||
<p>{{ _h("License:") }} <a class="grey-text text-lighten-4" href="https://www.gnu.org/licenses/agpl-3.0.en.html" rel="noopener noreferrer">AGPLv3</a></p>
|
||||
{% if web_version %}
|
||||
<p>
|
||||
This public API should be used for testing, personal or infrequent use. If you're going to run an application in production, please <a href="https://github.com/LibreTranslate/LibreTranslate" class="grey-text text-lighten-4" rel="noopener noreferrer">host your own server</a> or <a class="grey-text text-lighten-4" href="{{ get_api_key_link if get_api_key_link else 'https://github.com/LibreTranslate/LibreTranslate#mirrors' }}" rel="noopener noreferrer">get an API key</a>.
|
||||
{{ _h("This public API should be used for testing, personal or infrequent use. If you're going to run an application in production, please %(host_server)s or %(get_api_key)s.", host_server='<a href="https://github.com/LibreTranslate/LibreTranslate" class="grey-text text-lighten-4" rel="noopener noreferrer">' + _h("host your own server") + '</a>', get_api_key='<a class="grey-text text-lighten-4" href="' + (get_api_key_link if get_api_key_link else "https://github.com/LibreTranslate/LibreTranslate#mirrors") + '" rel="noopener noreferrer">' + _h("get an API key") + '</a>') }}
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
@ -308,7 +342,7 @@
|
||||
</div>
|
||||
<div class="footer-copyright center">
|
||||
<p class="white-text">
|
||||
Made with ❤ by <a class="white-text" href="https://github.com/LibreTranslate/LibreTranslate/graphs/contributors" rel="noopener noreferrer">LibreTranslate Contributors</a> and powered by <a class="white-text text-lighten-3" href="https://github.com/argosopentech/argos-translate/" rel="noopener noreferrer">Argos Translate</a>
|
||||
{{ _h("Made with %(heart)s by %(contributors)s and powered by %(engine)s", heart='❤', contributors='<a class="white-text" href="https://github.com/LibreTranslate/LibreTranslate/graphs/contributors" rel="noopener noreferrer">%s</a>' % _h("%(libretranslate)s Contributors", libretranslate="LibreTranslate"), engine='<a class="white-text text-lighten-3" href="https://github.com/argosopentech/argos-translate/" rel="noopener noreferrer">Argos Translate</a>') }}
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
@ -320,7 +354,7 @@
|
||||
window.Prism.manual = true;
|
||||
// @license-end
|
||||
</script>
|
||||
<script src="{{ url_for('static', filename='js/prism.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/app.js') }}?v={{ version }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/prism.min.js') }}"></script>
|
||||
<script src="js/app.js?v={{ version }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,22 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>jslicense-labels1 for LibreTranslate</title>
|
||||
</head>
|
||||
<body>
|
||||
<h3>Weblabels</h3>
|
||||
<table id="jslicense-labels1" border="1">
|
||||
<tr>
|
||||
<td><a href="{{ url_for('static', filename='js/vue@2.js') }}">Vue.js</a></td>
|
||||
<td><a href="http://www.jclark.com/xml/copying.txt">Expat</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="{{ url_for('static', filename='js/prism.min.js') }}">prism.min.js</a></td>
|
||||
<td><a href="http://www.jclark.com/xml/copying.txt">Expat</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="{{ url_for('static', filename='js/materialize.min.js') }}">materialize.min.js</a></td>
|
||||
<td><a href="http://www.jclark.com/xml/copying.txt">Expat</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
@ -3,6 +3,8 @@ Flask==2.2.2
|
||||
flask-swagger==0.2.14
|
||||
flask-swagger-ui==4.11.1
|
||||
Flask-Limiter==2.6.3
|
||||
Flask-Babel==2.0.0
|
||||
Flask-Session==0.4.0
|
||||
waitress==2.1.2
|
||||
expiringdict==1.2.2
|
||||
LTpycld2==0.42
|
||||
@ -16,3 +18,4 @@ Werkzeug==2.2.2
|
||||
requests==2.28.1
|
||||
redis==4.3.4
|
||||
prometheus-client==0.15.0
|
||||
polib==1.1.1
|
||||
|
2
setup.py
2
setup.py
@ -13,7 +13,7 @@ setup(
|
||||
packages=find_packages(),
|
||||
# packages=find_packages(include=['openpredict']),
|
||||
# package_dir={'openpredict': 'openpredict'},
|
||||
package_data={'': ['static/*', 'static/**/*', 'templates/*']},
|
||||
package_data={'': ['static/*', 'static/**/*', 'templates/*', 'locales/**/meta.json', 'locales/**/**/*.mo']},
|
||||
include_package_data=True,
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
|
136
update_locales.py
Executable file
136
update_locales.py
Executable file
@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env python
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
import polib
|
||||
import json
|
||||
from babel.messages.frontend import main as pybabel
|
||||
from libretranslate.language import load_languages, improve_translation_formatting
|
||||
from libretranslate.locales import get_available_locale_codes, swag_eval
|
||||
from translatehtml import translate_html
|
||||
from libretranslate.app import get_version, create_app
|
||||
from libretranslate.main import get_args
|
||||
from flask_swagger import swagger
|
||||
|
||||
# Update strings
|
||||
if __name__ == "__main__":
|
||||
print("Loading languages")
|
||||
languages = load_languages()
|
||||
en_lang = next((l for l in languages if l.code == 'en'), None)
|
||||
if en_lang is None:
|
||||
print("Error: English model not found. You need it to run this script.")
|
||||
exit(1)
|
||||
|
||||
locales_dir = os.path.join("libretranslate", "locales")
|
||||
if not os.path.isdir(locales_dir):
|
||||
os.makedirs(locales_dir)
|
||||
|
||||
# Dump language list so it gets picked up by pybabel
|
||||
langs_file = os.path.join(locales_dir, ".langs.py")
|
||||
with open(langs_file, 'w') as f:
|
||||
for l in languages:
|
||||
f.write("_(%s)\n" % json.dumps(l.name))
|
||||
print("Wrote %s" % langs_file)
|
||||
|
||||
# Dump swagger strings
|
||||
args = get_args()
|
||||
app = create_app(args)
|
||||
swag = swagger(app)
|
||||
|
||||
swag_strings = []
|
||||
def add_swag_string(s):
|
||||
if not s in swag_strings:
|
||||
swag_strings.append(s)
|
||||
swag_eval(swag, add_swag_string)
|
||||
|
||||
swag_file = os.path.join(locales_dir, ".swag.py")
|
||||
with open(swag_file, 'w') as f:
|
||||
for ss in swag_strings:
|
||||
f.write("_(%s)\n" % json.dumps(ss))
|
||||
print("Wrote %s" % swag_file)
|
||||
|
||||
messagespot = os.path.join(locales_dir, "messages.pot")
|
||||
print("Updating %s" % messagespot)
|
||||
sys.argv = ["", "extract", "-F", "babel.cfg", "-k", "_e _h",
|
||||
"--copyright-holder", "LibreTranslate Authors",
|
||||
"--project", "LibreTranslate",
|
||||
"--version", get_version(),
|
||||
"-o", messagespot, "libretranslate"]
|
||||
pybabel()
|
||||
|
||||
lang_codes = [l.code for l in languages if l != "en"]
|
||||
|
||||
# Init/update
|
||||
for l in lang_codes:
|
||||
cmd = "init"
|
||||
if os.path.isdir(os.path.join(locales_dir, l, "LC_MESSAGES")):
|
||||
cmd = "update"
|
||||
|
||||
sys.argv = ["", cmd, "-i", messagespot, "-d", locales_dir, "-l", l]
|
||||
pybabel()
|
||||
|
||||
meta_file = os.path.join(locales_dir, l, "meta.json")
|
||||
if not os.path.isfile(meta_file):
|
||||
with open(meta_file, 'w') as f:
|
||||
f.write(json.dumps({
|
||||
'name': next((lang.name for lang in languages if lang.code == l)),
|
||||
'reviewed': False
|
||||
}, indent=4))
|
||||
print("Wrote %s" % meta_file)
|
||||
|
||||
# Automatically translate strings with libretranslate
|
||||
# when a language model is available and a string is empty
|
||||
|
||||
locales = get_available_locale_codes(only_reviewed=False)
|
||||
print(locales)
|
||||
for locale in locales:
|
||||
if locale == 'en':
|
||||
continue
|
||||
|
||||
tgt_lang = next((l for l in languages if l.code == locale), None)
|
||||
|
||||
if tgt_lang is None:
|
||||
# We cannot translate
|
||||
continue
|
||||
|
||||
translator = en_lang.get_translation(tgt_lang)
|
||||
|
||||
messages_file = os.path.join(locales_dir, locale, "LC_MESSAGES", 'messages.po')
|
||||
if os.path.isfile(messages_file):
|
||||
print("Translating '%s'" % locale)
|
||||
pofile = polib.pofile(messages_file)
|
||||
c = 0
|
||||
|
||||
for entry in pofile.untranslated_entries():
|
||||
text = entry.msgid
|
||||
|
||||
# Extract placeholders
|
||||
placeholders = re.findall(r'%\(?[^\)]*\)?s', text)
|
||||
|
||||
for p in range(0, len(placeholders)):
|
||||
text = text.replace(placeholders[p], "<x>%s</x>" % p)
|
||||
|
||||
if len(placeholders) > 0:
|
||||
translated = str(translate_html(translator, text))
|
||||
else:
|
||||
translated = improve_translation_formatting(text, translator.translate(text))
|
||||
|
||||
# Restore placeholders
|
||||
for p in range(0, len(placeholders)):
|
||||
tag = "<x>%s</x>" % p
|
||||
if tag in translated:
|
||||
translated = translated.replace(tag, placeholders[p])
|
||||
else:
|
||||
# Meh, append
|
||||
translated += " " + placeholders[p]
|
||||
|
||||
print(entry.msgid, " --> ", translated)
|
||||
entry.msgstr = translated
|
||||
c += 1
|
||||
|
||||
if c > 0:
|
||||
pofile.save(messages_file)
|
||||
print("Saved %s" % messages_file)
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user