From 05900ff556a592398cc725b69aebfd3a48f54a60 Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Wed, 4 Jan 2023 12:15:18 -0500 Subject: [PATCH 01/21] Translation scripts --- babel.cfg | 2 ++ compile_translations.py | 16 ++++++++++ libretranslate/app.py | 21 +++++++++++-- .../js/app.js => templates/app.js.template} | 2 +- libretranslate/templates/index.html | 2 +- libretranslate/translations/.gitignore | 1 + requirements.txt | 1 + update_translations.py | 31 +++++++++++++++++++ 8 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 babel.cfg create mode 100755 compile_translations.py rename libretranslate/{static/js/app.js => templates/app.js.template} (99%) create mode 100644 libretranslate/translations/.gitignore create mode 100755 update_translations.py diff --git a/babel.cfg b/babel.cfg new file mode 100644 index 0000000..b335d31 --- /dev/null +++ b/babel.cfg @@ -0,0 +1,2 @@ +[python: **.py] +[jinja2: **/templates/**] \ No newline at end of file diff --git a/compile_translations.py b/compile_translations.py new file mode 100755 index 0000000..55076d3 --- /dev/null +++ b/compile_translations.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python +import sys +import os +from babel.messages.frontend import main as pybabel + +if __name__ == "__main__": + translations_dir = os.path.join("libretranslate", "translations") + if not os.path.isdir(translations_dir): + os.makedirs(translations_dir) + + print("Compiling translations") + sys.argv = ["", "compile", "-d", translations_dir] + pybabel() + + + diff --git a/libretranslate/app.py b/libretranslate/app.py index 6375a05..73be457 100644 --- a/libretranslate/app.py +++ b/libretranslate/app.py @@ -15,6 +15,7 @@ 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 libretranslate import flood, remove_translated_files, security from libretranslate.language import detect_languages, improve_translation_formatting @@ -53,7 +54,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 +122,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( @@ -294,6 +295,14 @@ def create_app(args): return render_template("javascript-licenses.html") + @bp.route("/static/js/app.js") + @limiter.exempt + def appjs(): + if args.disable_web_ui: + abort(404) + + return render_template("app.js.template") + @bp.get("/languages") @limiter.exempt def langs(): @@ -1002,12 +1011,18 @@ def create_app(args): swag["info"]["version"] = get_version() swag["info"]["title"] = "LibreTranslate" - @app.route(API_URL) @limiter.exempt def spec(): return jsonify(swag) + babel = Babel(app) + @babel.localeselector + def get_locale(): + # TODO: populate from available locales + return request.accept_languages.best_match(['en', 'it']) + + # Call factory function to create our blueprint swaggerui_blueprint = get_swaggerui_blueprint(SWAGGER_URL, API_URL) if args.url_prefix: diff --git a/libretranslate/static/js/app.js b/libretranslate/templates/app.js.template similarity index 99% rename from libretranslate/static/js/app.js rename to libretranslate/templates/app.js.template index 6957b04..1c61fa1 100644 --- a/libretranslate/static/js/app.js +++ b/libretranslate/templates/app.js.template @@ -28,7 +28,7 @@ document.addEventListener('DOMContentLoaded', function(){ detectedLangText: "", - copyTextLabel: "Copy text", + copyTextLabel: {{ _("Copy text") }}, suggestions: false, isSuggesting: false, diff --git a/libretranslate/templates/index.html b/libretranslate/templates/index.html index 6061fd1..cc596cb 100644 --- a/libretranslate/templates/index.html +++ b/libretranslate/templates/index.html @@ -3,7 +3,7 @@ - LibreTranslate - Free and Open Source Machine Translation API + LibreTranslate - {{ _("Free and Open Source Machine Translation API") }} diff --git a/libretranslate/translations/.gitignore b/libretranslate/translations/.gitignore new file mode 100644 index 0000000..d0f6ec9 --- /dev/null +++ b/libretranslate/translations/.gitignore @@ -0,0 +1 @@ +**/*.mo diff --git a/requirements.txt b/requirements.txt index bb13088..f81df00 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,6 +3,7 @@ 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 waitress==2.1.2 expiringdict==1.2.2 LTpycld2==0.42 diff --git a/update_translations.py b/update_translations.py new file mode 100755 index 0000000..ecc22d9 --- /dev/null +++ b/update_translations.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +import sys +import os +from babel.messages.frontend import main as pybabel +from libretranslate.language import load_languages + +# Update strings +if __name__ == "__main__": + translations_dir = os.path.join("libretranslate", "translations") + if not os.path.isdir(translations_dir): + os.makedirs(translations_dir) + + messagespot = os.path.join(translations_dir, "messages.pot") + print("Updating %s" % messagespot) + sys.argv = ["", "extract", "-F", "babel.cfg", "-o", messagespot, "libretranslate"] + pybabel() + + # Load list of languages + print("Loading languages") + languages = [l.code for l in load_languages() if l != "en"] + print(languages) + languages = ["it"] + + for l in languages: + cmd = "init" + if os.path.isdir(os.path.join(translations_dir, l)): + cmd = "update" + + sys.argv = ["", cmd, "-i", messagespot, "-d", translations_dir, "-l", l] + pybabel() + From 50c9b625952a04fb0be9c8a5b04d124179f3cd5f Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Wed, 4 Jan 2023 12:40:00 -0500 Subject: [PATCH 02/21] PoC translation working --- libretranslate/app.py | 3 ++ libretranslate/templates/app.js.template | 4 +- .../translations/it/LC_MESSAGES/messages.po | 41 +++++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 libretranslate/translations/it/LC_MESSAGES/messages.po diff --git a/libretranslate/app.py b/libretranslate/app.py index 73be457..52e818f 100644 --- a/libretranslate/app.py +++ b/libretranslate/app.py @@ -1022,6 +1022,9 @@ def create_app(args): # TODO: populate from available locales return request.accept_languages.best_match(['en', 'it']) + def gettext_escaped(*args, **kwargs): + return _(*args, **kwargs).replace("'", "\\'") + app.jinja_env.globals.update(_e=gettext_escaped) # Call factory function to create our blueprint swaggerui_blueprint = get_swaggerui_blueprint(SWAGGER_URL, API_URL) diff --git a/libretranslate/templates/app.js.template b/libretranslate/templates/app.js.template index 1c61fa1..57dde04 100644 --- a/libretranslate/templates/app.js.template +++ b/libretranslate/templates/app.js.template @@ -28,7 +28,7 @@ document.addEventListener('DOMContentLoaded', function(){ detectedLangText: "", - copyTextLabel: {{ _("Copy text") }}, + copyTextLabel: '{{ _e("Copy text") }}', suggestions: false, isSuggesting: false, @@ -69,7 +69,7 @@ document.addEventListener('DOMContentLoaded', function(){ } } } else { - self.error = "Cannot load /frontend/settings"; + self.error = '{{ _e("Cannot load %(url)s", url="/frontend/settings") }}'; self.loading = false; } }; diff --git a/libretranslate/translations/it/LC_MESSAGES/messages.po b/libretranslate/translations/it/LC_MESSAGES/messages.po new file mode 100644 index 0000000..9c65540 --- /dev/null +++ b/libretranslate/translations/it/LC_MESSAGES/messages.po @@ -0,0 +1,41 @@ +# Italian translations for PROJECT. +# Copyright (C) 2023 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2023. +# +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2023-01-04 12:27-0500\n" +"PO-Revision-Date: 2023-01-04 12:27-0500\n" +"Last-Translator: FULL NAME \n" +"Language: it\n" +"Language-Team: it \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:57 +msgid "Invalid JSON format" +msgstr "" + +#: libretranslate/app.py:125 +msgid "Auto Detect" +msgstr "" + +#: libretranslate/templates/app.js.template:31 +msgid "Copy text" +msgstr "Copia testo" + +#: libretranslate/templates/app.js.template:72 +#, python-format +msgid "Cannot load %(url)s" +msgstr "Impossibile caricare' %(url)s" + +#: libretranslate/templates/index.html:6 +msgid "Free and Open Source Machine Translation API" +msgstr "API di traduzione automatica open source" + From 3cbbd8ae16c5426534de5b14ea24b7b426f55f9c Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Wed, 4 Jan 2023 15:36:26 -0500 Subject: [PATCH 03/21] Auto self-translation --- compile_locales.py | 16 ++++ compile_translations.py | 16 ---- libretranslate/app.py | 5 +- libretranslate/locales.py | 9 ++ .../{translations => locales}/.gitignore | 0 .../it/LC_MESSAGES/messages.po | 17 ++-- libretranslate/templates/app.js.template | 4 +- requirements.txt | 1 + update_locales.py | 96 +++++++++++++++++++ update_translations.py | 31 ------ 10 files changed, 135 insertions(+), 60 deletions(-) create mode 100755 compile_locales.py delete mode 100755 compile_translations.py create mode 100644 libretranslate/locales.py rename libretranslate/{translations => locales}/.gitignore (100%) rename libretranslate/{translations => locales}/it/LC_MESSAGES/messages.po (82%) create mode 100755 update_locales.py delete mode 100755 update_translations.py diff --git a/compile_locales.py b/compile_locales.py new file mode 100755 index 0000000..300bbb0 --- /dev/null +++ b/compile_locales.py @@ -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", "-d", locales_dir] + pybabel() + + + diff --git a/compile_translations.py b/compile_translations.py deleted file mode 100755 index 55076d3..0000000 --- a/compile_translations.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env python -import sys -import os -from babel.messages.frontend import main as pybabel - -if __name__ == "__main__": - translations_dir = os.path.join("libretranslate", "translations") - if not os.path.isdir(translations_dir): - os.makedirs(translations_dir) - - print("Compiling translations") - sys.argv = ["", "compile", "-d", translations_dir] - pybabel() - - - diff --git a/libretranslate/app.py b/libretranslate/app.py index 52e818f..964a15d 100644 --- a/libretranslate/app.py +++ b/libretranslate/app.py @@ -19,6 +19,7 @@ from flask_babel import Babel, gettext as _ from libretranslate import flood, remove_translated_files, security from libretranslate.language import detect_languages, improve_translation_formatting +from libretranslate.locales import get_available_locales from .api_keys import Database, RemoteDatabase from .suggestions import Database as SuggestionsDatabase @@ -1020,11 +1021,11 @@ def create_app(args): @babel.localeselector def get_locale(): # TODO: populate from available locales - return request.accept_languages.best_match(['en', 'it']) + return request.accept_languages.best_match(get_available_locales()) def gettext_escaped(*args, **kwargs): return _(*args, **kwargs).replace("'", "\\'") - app.jinja_env.globals.update(_e=gettext_escaped) + app.jinja_env.globals.update(N_=gettext_escaped) # Call factory function to create our blueprint swaggerui_blueprint = get_swaggerui_blueprint(SWAGGER_URL, API_URL) diff --git a/libretranslate/locales.py b/libretranslate/locales.py new file mode 100644 index 0000000..b3deb4c --- /dev/null +++ b/libretranslate/locales.py @@ -0,0 +1,9 @@ +import os +from functools import cache + +@cache +def get_available_locales(): + locales_dir = os.path.join(os.path.dirname(__file__), 'locales') + dirs = [os.path.join(locales_dir, d) for d in os.listdir(locales_dir)] + + return ['en'] + [os.path.basename(d) for d in dirs if os.path.isdir(os.path.join(d, 'LC_MESSAGES'))] \ No newline at end of file diff --git a/libretranslate/translations/.gitignore b/libretranslate/locales/.gitignore similarity index 100% rename from libretranslate/translations/.gitignore rename to libretranslate/locales/.gitignore diff --git a/libretranslate/translations/it/LC_MESSAGES/messages.po b/libretranslate/locales/it/LC_MESSAGES/messages.po similarity index 82% rename from libretranslate/translations/it/LC_MESSAGES/messages.po rename to libretranslate/locales/it/LC_MESSAGES/messages.po index 9c65540..092dcc5 100644 --- a/libretranslate/translations/it/LC_MESSAGES/messages.po +++ b/libretranslate/locales/it/LC_MESSAGES/messages.po @@ -7,24 +7,24 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2023-01-04 12:27-0500\n" +"POT-Creation-Date: 2023-01-04 15:34-0500\n" "PO-Revision-Date: 2023-01-04 12:27-0500\n" "Last-Translator: FULL NAME \n" -"Language: it\n" "Language-Team: it \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:57 +#: libretranslate/app.py:58 msgid "Invalid JSON format" -msgstr "" +msgstr "Formato JSON non valido" -#: libretranslate/app.py:125 +#: libretranslate/app.py:126 msgid "Auto Detect" -msgstr "" +msgstr "Rilevamento automatico" #: libretranslate/templates/app.js.template:31 msgid "Copy text" @@ -33,9 +33,8 @@ msgstr "Copia testo" #: libretranslate/templates/app.js.template:72 #, python-format msgid "Cannot load %(url)s" -msgstr "Impossibile caricare' %(url)s" +msgstr "Non riesco a caricare %(url)s" #: libretranslate/templates/index.html:6 msgid "Free and Open Source Machine Translation API" msgstr "API di traduzione automatica open source" - diff --git a/libretranslate/templates/app.js.template b/libretranslate/templates/app.js.template index 57dde04..1aae136 100644 --- a/libretranslate/templates/app.js.template +++ b/libretranslate/templates/app.js.template @@ -28,7 +28,7 @@ document.addEventListener('DOMContentLoaded', function(){ detectedLangText: "", - copyTextLabel: '{{ _e("Copy text") }}', + copyTextLabel: '{{ N_("Copy text") }}', suggestions: false, isSuggesting: false, @@ -69,7 +69,7 @@ document.addEventListener('DOMContentLoaded', function(){ } } } else { - self.error = '{{ _e("Cannot load %(url)s", url="/frontend/settings") }}'; + self.error = '{{ N_("Cannot load %(url)s", url="/frontend/settings") }}'; self.loading = false; } }; diff --git a/requirements.txt b/requirements.txt index f81df00..5f21574 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,3 +17,4 @@ Werkzeug==2.2.2 requests==2.28.1 redis==4.3.4 prometheus-client==0.15.0 +polib==1.1.1 diff --git a/update_locales.py b/update_locales.py new file mode 100755 index 0000000..c8f6ebd --- /dev/null +++ b/update_locales.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python +import sys +import os +import re +import polib +from babel.messages.frontend import main as pybabel +from libretranslate.language import load_languages, improve_translation_formatting +from libretranslate.locales import get_available_locales +from translatehtml import translate_html + +# Update strings +if __name__ == "__main__": + locales_dir = os.path.join("libretranslate", "locales") + if not os.path.isdir(locales_dir): + os.makedirs(locales_dir) + + messagespot = os.path.join(locales_dir, "messages.pot") + print("Updating %s" % messagespot) + sys.argv = ["", "extract", "-F", "babel.cfg", "-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 + + # Init/update + for l in lang_codes: + cmd = "init" + if os.path.isdir(os.path.join(locales_dir, l)): + cmd = "update" + + sys.argv = ["", cmd, "-i", messagespot, "-d", locales_dir, "-l", l] + pybabel() + + # Automatically translate strings with libretranslate + # when a language model is available and a string is empty + + locales = get_available_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], "%s" % 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 = "%s" % 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) + + + diff --git a/update_translations.py b/update_translations.py deleted file mode 100755 index ecc22d9..0000000 --- a/update_translations.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python -import sys -import os -from babel.messages.frontend import main as pybabel -from libretranslate.language import load_languages - -# Update strings -if __name__ == "__main__": - translations_dir = os.path.join("libretranslate", "translations") - if not os.path.isdir(translations_dir): - os.makedirs(translations_dir) - - messagespot = os.path.join(translations_dir, "messages.pot") - print("Updating %s" % messagespot) - sys.argv = ["", "extract", "-F", "babel.cfg", "-o", messagespot, "libretranslate"] - pybabel() - - # Load list of languages - print("Loading languages") - languages = [l.code for l in load_languages() if l != "en"] - print(languages) - languages = ["it"] - - for l in languages: - cmd = "init" - if os.path.isdir(os.path.join(translations_dir, l)): - cmd = "update" - - sys.argv = ["", cmd, "-i", messagespot, "-d", translations_dir, "-l", l] - pybabel() - From 19c3c04ca64373671eacfb8ab833421c3c3569bb Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Wed, 4 Jan 2023 17:54:07 -0500 Subject: [PATCH 04/21] Translated index.html --- libretranslate/app.py | 19 +- libretranslate/locales.py | 24 ++- .../locales/it/LC_MESSAGES/messages.po | 30 +++- libretranslate/templates/app.js.template | 4 +- libretranslate/templates/index.html | 167 +++++++++--------- .../templates/javascript-licenses.html | 22 --- update_locales.py | 7 +- 7 files changed, 144 insertions(+), 129 deletions(-) delete mode 100644 libretranslate/templates/javascript-licenses.html diff --git a/libretranslate/app.py b/libretranslate/app.py index 964a15d..65c70a3 100644 --- a/libretranslate/app.py +++ b/libretranslate/app.py @@ -19,7 +19,7 @@ from flask_babel import Babel, gettext as _ from libretranslate import flood, remove_translated_files, security from libretranslate.language import detect_languages, improve_translation_formatting -from libretranslate.locales import get_available_locales +from libretranslate.locales import get_available_locales, gettext_escaped, gettext_html from .api_keys import Database, RemoteDatabase from .suggestions import Database as SuggestionsDatabase @@ -288,14 +288,6 @@ def create_app(args): url_prefix=args.url_prefix ) - @bp.get("/javascript-licenses") - @limiter.exempt - def javascript_licenses(): - if args.disable_web_ui: - abort(404) - - return render_template("javascript-licenses.html") - @bp.route("/static/js/app.js") @limiter.exempt def appjs(): @@ -1017,15 +1009,16 @@ def create_app(args): def spec(): return jsonify(swag) + + app.config["BABEL_TRANSLATION_DIRECTORIES"] = 'locales' babel = Babel(app) @babel.localeselector def get_locale(): - # TODO: populate from available locales return request.accept_languages.best_match(get_available_locales()) - def gettext_escaped(*args, **kwargs): - return _(*args, **kwargs).replace("'", "\\'") - app.jinja_env.globals.update(N_=gettext_escaped) + + + 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) diff --git a/libretranslate/locales.py b/libretranslate/locales.py index b3deb4c..759ef4b 100644 --- a/libretranslate/locales.py +++ b/libretranslate/locales.py @@ -1,9 +1,31 @@ import os from functools import cache +from flask_babel import gettext as _ +from markupsafe import escape, Markup @cache def get_available_locales(): locales_dir = os.path.join(os.path.dirname(__file__), 'locales') dirs = [os.path.join(locales_dir, d) for d in os.listdir(locales_dir)] - return ['en'] + [os.path.basename(d) for d in dirs if os.path.isdir(os.path.join(d, 'LC_MESSAGES'))] \ No newline at end of file + return ['en'] + [os.path.basename(d) for d in dirs if os.path.isdir(os.path.join(d, 'LC_MESSAGES'))] + +# Javascript code should use _e instead of _ +def gettext_escaped(text, **variables): + return _(text, **variables).replace("'", "\\'") + +# 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) \ No newline at end of file diff --git a/libretranslate/locales/it/LC_MESSAGES/messages.po b/libretranslate/locales/it/LC_MESSAGES/messages.po index 092dcc5..eeb23b3 100644 --- a/libretranslate/locales/it/LC_MESSAGES/messages.po +++ b/libretranslate/locales/it/LC_MESSAGES/messages.po @@ -7,15 +7,15 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2023-01-04 15:34-0500\n" +"POT-Creation-Date: 2023-01-04 16:34-0500\n" "PO-Revision-Date: 2023-01-04 12:27-0500\n" "Last-Translator: FULL NAME \n" -"Language-Team: it \n" "Language: it\n" +"Language-Team: it \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" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Generated-By: Babel 2.11.0\n" #: libretranslate/app.py:58 @@ -35,6 +35,24 @@ msgstr "Copia testo" msgid "Cannot load %(url)s" msgstr "Non riesco a caricare %(url)s" -#: libretranslate/templates/index.html:6 -msgid "Free and Open Source Machine Translation API" -msgstr "API di traduzione automatica open source" +#: 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/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" +msgstr "traduzione" + +#: libretranslate/templates/index.html:9 +msgid "api" +msgstr "api" + diff --git a/libretranslate/templates/app.js.template b/libretranslate/templates/app.js.template index 1aae136..57dde04 100644 --- a/libretranslate/templates/app.js.template +++ b/libretranslate/templates/app.js.template @@ -28,7 +28,7 @@ document.addEventListener('DOMContentLoaded', function(){ detectedLangText: "", - copyTextLabel: '{{ N_("Copy text") }}', + copyTextLabel: '{{ _e("Copy text") }}', suggestions: false, isSuggesting: false, @@ -69,7 +69,7 @@ document.addEventListener('DOMContentLoaded', function(){ } } } else { - self.error = '{{ N_("Cannot load %(url)s", url="/frontend/settings") }}'; + self.error = '{{ _e("Cannot load %(url)s", url="/frontend/settings") }}'; self.loading = false; } }; diff --git a/libretranslate/templates/index.html b/libretranslate/templates/index.html index cc596cb..be8e993 100644 --- a/libretranslate/templates/index.html +++ b/libretranslate/templates/index.html @@ -3,10 +3,10 @@ - LibreTranslate - {{ _("Free and Open Source Machine Translation API") }} + {{ _h("LibreTranslate - Free and Open Source Machine Translation API") }} - - + + @@ -23,11 +23,11 @@ - + - + @@ -58,28 +58,28 @@ @@ -116,7 +116,7 @@ warning

[[ error ]]

@@ -130,22 +130,22 @@
-

Translation API

+

{{ _h("Translation API") }}

- Translate from - [[ detectedLangText ]] + {{ _h("Translate from") }} + [[ detectedLangText ]]