Tagged all strings

This commit is contained in:
Piero Toffanin 2023-01-05 13:12:35 -05:00
parent 19c3c04ca6
commit edd3d6931d
8 changed files with 492 additions and 102 deletions

View file

@ -9,7 +9,7 @@ if __name__ == "__main__":
os.makedirs(locales_dir)
print("Compiling locales")
sys.argv = ["", "compile", "-d", locales_dir]
sys.argv = ["", "compile", "-f", "-d", locales_dir]
pybabel()

View file

@ -15,11 +15,11 @@ from flask_swagger_ui import get_swaggerui_blueprint
from translatehtml import translate_html
from werkzeug.utils import secure_filename
from werkzeug.exceptions import HTTPException
from flask_babel import Babel, gettext as _
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 get_available_locales, gettext_escaped, gettext_html
from libretranslate.locales import _, _lazy, get_available_locales, gettext_escaped, gettext_html
from .api_keys import Database, RemoteDatabase
from .suggestions import Database as SuggestionsDatabase
@ -188,7 +188,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)
@ -206,7 +206,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()
@ -215,16 +215,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,
@ -264,7 +264,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):
@ -294,7 +294,8 @@ def create_app(args):
if args.disable_web_ui:
abort(404)
return render_template("app.js.template")
return render_template("app.js.template",
get_api_key_link=args.get_api_key_link)
@bp.get("/languages")
@limiter.exempt
@ -325,7 +326,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
@ -454,11 +455,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)
@ -467,8 +468,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:
@ -480,8 +480,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":
@ -514,18 +513,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:
@ -533,7 +532,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))
@ -557,7 +556,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))
@ -578,7 +577,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
@ -665,36 +664,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)
@ -719,7 +718,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:
@ -727,7 +726,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:
@ -820,9 +819,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")
@ -830,7 +826,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))
@ -903,11 +899,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),
},
},
}
@ -971,7 +967,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")
@ -979,13 +975,13 @@ 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})
@ -1016,8 +1012,6 @@ def create_app(args):
def get_locale():
return request.accept_languages.best_match(get_available_locales())
app.jinja_env.globals.update(_e=gettext_escaped, _h=gettext_html)
# Call factory function to create our blueprint

View file

@ -1,6 +1,9 @@
import os
import json
from functools import cache
from flask_babel import gettext as _
from flask_babel import lazy_gettext as _lazy
from markupsafe import escape, Markup
@cache
@ -12,7 +15,7 @@ def get_available_locales():
# Javascript code should use _e instead of _
def gettext_escaped(text, **variables):
return _(text, **variables).replace("'", "\\'")
return json.dumps(_(text, **variables))
# HTML should be escaped using _h instead of _
def gettext_html(text, **variables):

View file

@ -1 +1,2 @@
**/*.mo
.langs.py

View file

@ -1,52 +1,309 @@
# Italian translations for PROJECT.
# Copyright (C) 2023 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# 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: PROJECT VERSION\n"
"Project-Id-Version: LibreTranslate 1.3.8\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2023-01-04 16:34-0500\n"
"PO-Revision-Date: 2023-01-04 12:27-0500\n"
"POT-Creation-Date: 2023-01-05 13:11-0500\n"
"PO-Revision-Date: 2023-01-05 13:11-0500\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: it\n"
"Language-Team: it <LL@li.org>\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\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:58
msgid "Invalid JSON format"
msgstr "Formato JSON non valido"
#: libretranslate/app.py:126
#: libretranslate/app.py:126 libretranslate/templates/app.js.template:427
msgid "Auto Detect"
msgstr "Rilevamento automatico"
#: libretranslate/app.py:191
msgid "Unauthorized"
msgstr "Non autorizzato"
#: libretranslate/app.py:209
msgid "Too many request limits violations"
msgstr "Troppe richieste limitano le violazioni"
#: libretranslate/app.py:218
msgid "Invalid API key"
msgstr "Chiave API non valida"
#: libretranslate/app.py:225
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:227
#, python-format
msgid "Visit %(url)s to get an API key"
msgstr "Visita %(url)s per ottenere una chiave API"
#: libretranslate/app.py:267
msgid "Slowdown:"
msgstr "Rallenta:"
#: libretranslate/app.py:458 libretranslate/app.py:460
#: libretranslate/app.py:462 libretranslate/app.py:674
#: libretranslate/app.py:676 libretranslate/app.py:678
#: libretranslate/app.py:829 libretranslate/app.py:978
#: libretranslate/app.py:980 libretranslate/app.py:982
#: libretranslate/app.py:984
#, python-format
msgid "Invalid request: missing %(name)s parameter"
msgstr "Richiesta non valida: mancante %(name)s parametro"
#: libretranslate/app.py:471 libretranslate/app.py:483
#, 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:516 libretranslate/app.py:521
#: libretranslate/app.py:691 libretranslate/app.py:696
#, python-format
msgid "%(lang)s is not supported"
msgstr "%(lang)s non è supportato"
#: libretranslate/app.py:527
#, python-format
msgid "%(format)s format is not supported"
msgstr "%(format)s formato non è supportato"
#: libretranslate/app.py:535 libretranslate/app.py:559
#, 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:580
#, python-format
msgid "Cannot translate text: %(text)s"
msgstr "Non può tradurre il testo: %(text)s"
#: libretranslate/app.py:667 libretranslate/app.py:721
msgid "Files translation are disabled on this server."
msgstr "La traduzione dei file è disabilitata su questo server."
#: libretranslate/app.py:681
msgid "Invalid request: empty file"
msgstr "Richiesta non valida: file vuoto"
#: libretranslate/app.py:684
msgid "Invalid request: file format not supported"
msgstr "Richiesta non valida: formato file non supportato"
#: libretranslate/app.py:729
msgid "Invalid filename"
msgstr "Invalid filename"
#: libretranslate/app.py:970
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/templates/app.js.template:31
#: 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/index.html:6 libretranslate/templates/index.html:26
msgid "LibreTranslate - Free and Open Source Machine Translation API"
msgstr "API di traduzione automatica open source < ' a"
#: 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/index.html:8 libretranslate/templates/index.html:30
#: libretranslate/templates/app.js.template:276
msgid "Copied"
msgstr "Copie"
#: libretranslate/templates/app.js.template:320
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."
"Thanks for your correction. Note the suggestion will not take effect right "
"away."
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."
"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:6
#: libretranslate/templates/index.html:26
#: libretranslate/templates/index.html:297
msgid "Free and Open Source Machine Translation API"
msgstr "API di traduzione automatica gratuita e open source"
#: libretranslate/templates/index.html:8
#: libretranslate/templates/index.html:30
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:9
msgid "translation"
@ -56,3 +313,132 @@ msgstr "traduzione"
msgid "api"
msgstr "api"
#: libretranslate/templates/index.html:64
#: libretranslate/templates/index.html:75
msgid "API Docs"
msgstr "API"
#: libretranslate/templates/index.html:66
#: libretranslate/templates/index.html:77
msgid "Get API Key"
msgstr "Ottieni API Chiave"
#: libretranslate/templates/index.html:68
#: libretranslate/templates/index.html:79
msgid "GitHub"
msgstr "GitHub"
#: libretranslate/templates/index.html:81
msgid "Set API Key"
msgstr "Set API Chiave"
#: libretranslate/templates/index.html:118
msgid "Dismiss"
msgstr "Oggetto"
#: libretranslate/templates/index.html:132
msgid "Translation API"
msgstr "API di traduzione"
#: libretranslate/templates/index.html:136
msgid "Translate Text"
msgstr "Traduzione"
#: libretranslate/templates/index.html:140
msgid "Translate Files"
msgstr "Traduci file"
#: libretranslate/templates/index.html:146
msgid "Translate from"
msgstr "Traduttore da"
#: libretranslate/templates/index.html:159
msgid "Translate into"
msgstr "Traduzione"
#: libretranslate/templates/index.html:171
msgid "Text to translate"
msgstr "Testo da tradurre"
#: libretranslate/templates/index.html:183
msgid "Translated text"
msgstr "Tradotto testo"
#: libretranslate/templates/index.html:191
msgid "Cancel"
msgstr "Annulla"
#: libretranslate/templates/index.html:194
msgid "Send"
msgstr "Invia"
#: libretranslate/templates/index.html:210
msgid "Supported file formats:"
msgstr "Formati di file supportati:"
#: libretranslate/templates/index.html:214
msgid "File"
msgstr "File"
#: libretranslate/templates/index.html:236
msgid "Translate"
msgstr "Traduttore"
#: libretranslate/templates/index.html:237
#: libretranslate/templates/index.html:281
msgid "Download"
msgstr "Scarica"
#: libretranslate/templates/index.html:256
msgid "Request"
msgstr "Richiesta"
#: libretranslate/templates/index.html:261
msgid "Response"
msgstr "Risposta"
#: libretranslate/templates/index.html:276
msgid "Open Source Machine Translation API"
msgstr "API di traduzione automatica Open Source"
#: libretranslate/templates/index.html:277
msgid "Self-Hosted. Offline Capable. Easy to Setup."
msgstr "Ossessionato. Offline Capable. Facile da configurare."
#: libretranslate/templates/index.html:296
msgid "LibreTranslate"
msgstr "LibreTranslate"
#: libretranslate/templates/index.html:298
msgid "License:"
msgstr "Licenza:"
#: libretranslate/templates/index.html:301
#, 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:301
msgid "host your own server"
msgstr "host tuo server"
#: libretranslate/templates/index.html:301
msgid "get an API key"
msgstr "ottenere una chiave API"
#: libretranslate/templates/index.html:309
#, 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:309
#, python-format
msgid "%(libretranslate)s Contributors"
msgstr "%(libretranslate)s Contributori"

View file

@ -28,7 +28,7 @@ document.addEventListener('DOMContentLoaded', function(){
detectedLangText: "",
copyTextLabel: '{{ _e("Copy text") }}',
copyTextLabel: {{ _e("Copy text") }},
suggestions: false,
isSuggesting: false,
@ -69,18 +69,18 @@ document.addEventListener('DOMContentLoaded', function(){
}
}
} else {
self.error = '{{ _e("Cannot load %(url)s", url="/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;
};
@ -273,10 +273,10 @@ document.addEventListener('DOMContentLoaded', function(){
document.execCommand("copy");
if (this.copyTextLabel === "Copy text"){
this.copyTextLabel = "Copied";
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);

View file

@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ _h("LibreTranslate - Free and Open Source Machine Translation API") }}</title>
<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="{{ _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') }}">
@ -23,7 +23,7 @@
<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="{{ _h('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" />
@ -57,14 +57,13 @@
<div class="nav-wrapper container">
<button data-target="nav-mobile" class="sidenav-trigger"><i class="material-icons">menu</i></button>
<a id="logo-container" href="/" class="brand-logo">
<img src="{{ url_for('static', filename='icon.svg') }}" alt="Logo for LibreTranslate" class="logo">
<span>{{ _h("LibreTranslate") }}</span>
<img src="{{ url_for('static', filename='icon.svg') }}" alt="LibreTranslate" class="logo">
<span>LibreTranslate</span>
</a>
<ul class="right hide-on-med-and-down">
<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>
<script>window.getApiKeyLink = "{{ get_api_key_link }}";</script>
{% endif %}
<li><a href="https://github.com/LibreTranslate/LibreTranslate" rel="noopener noreferrer">{{ _h("GitHub") }}</a></li>
{% if api_keys %}
@ -296,7 +295,7 @@
<div class="col l12 s12">
<h5 class="white-text">{{ _h("LibreTranslate") }}</h5>
<p class="grey-text text-lighten-4">{{ _h("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>{{ _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>
{{ _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>') }}
@ -307,7 +306,7 @@
</div>
<div class="footer-copyright center">
<p class="white-text">
{{ _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 Contributors"), engine='<a class="white-text text-lighten-3" href="https://github.com/argosopentech/argos-translate/" rel="noopener noreferrer">%s</a>' % _h('Argos Translate')) }}
{{ _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>

View file

@ -3,6 +3,7 @@ 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_locales
@ -11,10 +12,24 @@ from libretranslate.app import get_version
# 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)
messagespot = os.path.join(locales_dir, "messages.pot")
print("Updating %s" % messagespot)
sys.argv = ["", "extract", "-F", "babel.cfg", "-k", "_e _h",
@ -24,13 +39,7 @@ if __name__ == "__main__":
"-o", messagespot, "libretranslate"]
pybabel()
# Load list of languages
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)
lang_codes = [l.code for l in languages if l != "en"]
lang_codes = ["it"] # TODO REMOVE
@ -70,7 +79,7 @@ if __name__ == "__main__":
text = entry.msgid
# Extract placeholders
placeholders = re.findall(r'%\(?.*?\)?s', text)
placeholders = re.findall(r'%\(?[^\)]*\)?s', text)
for p in range(0, len(placeholders)):
text = text.replace(placeholders[p], "<x>%s</x>" % p)
@ -79,7 +88,7 @@ if __name__ == "__main__":
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