diff --git a/libretranslate/app.py b/libretranslate/app.py index ff02bd7..e0381e5 100644 --- a/libretranslate/app.py +++ b/libretranslate/app.py @@ -173,11 +173,11 @@ def filter_unique(seq, extra): def detect_translatable(src_texts): if isinstance(src_texts, list): return any(detect_translatable(t) for t in src_texts) - + for ch in src_texts: if not (ord(ch) in emojis): return True - + # All emojis return False @@ -190,7 +190,7 @@ def create_app(args): from libretranslate.language import load_languages swagger_url = args.url_prefix + "/docs" # Swagger UI (w/o trailing '/') - api_url = args.url_prefix + "/spec" + api_url = "/spec" bp = Blueprint('Main app', __name__) @@ -259,7 +259,7 @@ def create_app(args): return max(req_cost, int(math.ceil(getattr(request, 'duration', 0) / args.req_time_cost))) else: return req_cost - + def get_limits_key_func(): if args.api_keys: def func(): @@ -358,7 +358,7 @@ def create_app(args): 'alternatives': [], 'detectedLanguage': { 'confidence': 100, 'language': 'en' } }), 200)) - + if (args.require_api_key_fingerprint and key_missing): if flood.fingerprint_mismatch(ip, get_fingerprint()): @@ -470,7 +470,7 @@ def create_app(args): api_secret = secret.get_current_secret_js() else: api_secret = secret.get_bogus_secret_js() - + response = Response(render_template("app.js.template", url_prefix=args.url_prefix, get_api_key_link=args.get_api_key_link, @@ -516,8 +516,8 @@ def create_app(args): type: string description: Supported target language codes """ - return jsonify([{"code": model2iso(l.code), - "name": _lazy(l.name), + return jsonify([{"code": model2iso(l.code), + "name": _lazy(l.name), "targets": model2iso(language_pairs.get(l.code, [])) } for l in languages]) @@ -586,7 +586,7 @@ def create_app(args): default: 0 example: 3 required: false - description: Preferred number of alternative translations + description: Preferred number of alternative translations - in: formData name: api_key schema: @@ -704,7 +704,7 @@ def create_app(args): abort(400, description=_("Invalid request: missing %(name)s parameter", name='source')) if not target_lang: abort(400, description=_("Invalid request: missing %(name)s parameter", name='target')) - + try: num_alternatives = max(0, int(num_alternatives)) except ValueError: @@ -743,7 +743,7 @@ def create_app(args): if batch: request.req_cost = max(1, len(q)) - + translatable = detect_translatable(src_texts) if translatable: if source_lang == "auto": @@ -753,7 +753,7 @@ def create_app(args): detected_src_lang = {"confidence": 100.0, "language": source_lang} else: detected_src_lang = {"confidence": 0.0, "language": "en"} - + src_lang = next(iter([l for l in languages if l.code == detected_src_lang["language"]]), None) if src_lang is None: @@ -790,10 +790,10 @@ def create_app(args): else: translated_text = text # Cannot translate, send the original text back alternatives = [] - + batch_results.append(translated_text) batch_alternatives.append(alternatives) - + result = {"translatedText": batch_results} if source_lang == "auto": @@ -818,7 +818,7 @@ def create_app(args): else: translated_text = q # Cannot translate, send the original text back alternatives = [] - + result = {"translatedText": translated_text} if source_lang == "auto": @@ -1270,14 +1270,13 @@ def create_app(args): if args.debug: app.config["TEMPLATES_AUTO_RELOAD"] = True - if args.url_prefix: - app.register_blueprint(bp, url_prefix=args.url_prefix) - else: - app.register_blueprint(bp) + + app.register_blueprint(bp) limiter.init_app(app) swag = swagger(app) + swag["basePath"] = args.url_prefix if args.url_prefix != "" else "/" swag["info"]["version"] = get_version() swag["info"]["title"] = "LibreTranslate" swag["info"]["description"] = "Free and Open Source Machine Translation API." @@ -1301,10 +1300,9 @@ def create_app(args): 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) - if args.url_prefix: - app.register_blueprint(swaggerui_blueprint, url_prefix=swagger_url) - else: - app.register_blueprint(swaggerui_blueprint) + # The Blueprint is not using url_for which means the middleware does not work properly and we need to manually fix things + swaggerui_blueprint = get_swaggerui_blueprint(swagger_url, args.url_prefix + api_url) + swaggerui_blueprint.url_prefix = "/docs" + app.register_blueprint(swaggerui_blueprint) return app diff --git a/libretranslate/locales/ckb/LC_MESSAGES/messages.po b/libretranslate/locales/ckb/LC_MESSAGES/messages.po index 8ffd1a1..bea231a 100644 --- a/libretranslate/locales/ckb/LC_MESSAGES/messages.po +++ b/libretranslate/locales/ckb/LC_MESSAGES/messages.po @@ -9,14 +9,16 @@ msgstr "" "Project-Id-Version: LibreTranslate 1.7.1\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2025-04-18 14:43-0400\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Automatically generated\n" -"Language-Team: none\n" +"PO-Revision-Date: 2025-07-21 11:03+0000\n" +"Last-Translator: Halbast Abdullah \n" +"Language-Team: Kurdish (Central) \n" "Language: ckb\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" +"X-Generator: Weblate 5.13-dev\n" "Generated-By: Babel 2.12.1\n" #: libretranslate/app.py:93 @@ -25,11 +27,11 @@ msgstr "" #: libretranslate/app.py:209 libretranslate/templates/app.js.template:473 msgid "Auto Detect" -msgstr "" +msgstr "دۆزینەوەی خۆکار" #: libretranslate/app.py:311 msgid "Unauthorized" -msgstr "" +msgstr "ناسەلمێنراو" #: libretranslate/app.py:329 msgid "Too many request limits violations" @@ -37,7 +39,7 @@ msgstr "" #: libretranslate/app.py:336 msgid "Invalid API key" -msgstr "" +msgstr "کلیلی ئەی پی ئایی نادروست" #: libretranslate/app.py:371 msgid "Please contact the server operator to get an API key" diff --git a/libretranslate/main.py b/libretranslate/main.py index 4a279c7..2158198 100644 --- a/libretranslate/main.py +++ b/libretranslate/main.py @@ -4,6 +4,8 @@ import sys from libretranslate.app import create_app from libretranslate.default_values import DEFAULT_ARGUMENTS as DEFARGS +from werkzeug.serving import run_simple +from werkzeug.middleware.dispatcher import DispatcherMiddleware def get_args(): @@ -245,7 +247,7 @@ def get_args(): "--url-prefix", default=DEFARGS['URL_PREFIX'], type=str, - help="Add prefix to URL: example.com:5000/url-prefix/", + help="Add a prefix like /url-prefix to URL: example.com:5000/url-prefix/", ) args = parser.parse_args() if args.url_prefix and not args.url_prefix.startswith('/'): @@ -255,7 +257,17 @@ def get_args(): def main(): args = get_args() - app = create_app(args) + + if args.url_prefix: + def redirect(environ, start_response): + start_response("301 REDIRECT", [("Content-Type", "text/plain"), ("Location", args.url_prefix)]) + yield b"Redirect..." + + app = DispatcherMiddleware(redirect, { + args.url_prefix: create_app(args) + }) + else: + app = DispatcherMiddleware(create_app(args)) if '--wsgi' in sys.argv: return app @@ -265,7 +277,7 @@ def main(): args.host = "::" if args.debug: - app.run(host=args.host, port=args.port) + run_simple(args.host, args.port, app) else: from waitress import serve diff --git a/libretranslate/templates/app.js.template b/libretranslate/templates/app.js.template index f3c1ec0..0b66d61 100644 --- a/libretranslate/templates/app.js.template +++ b/libretranslate/templates/app.js.template @@ -54,7 +54,7 @@ document.addEventListener('DOMContentLoaded', function(){ const langsRequest = new XMLHttpRequest(); langsRequest.open("GET", BaseUrl + "/languages", true); - + settingsRequest.onload = function() { if (this.status >= 200 && this.status < 400) { self.settings = JSON.parse(this.response); @@ -79,18 +79,18 @@ document.addEventListener('DOMContentLoaded', function(){ } } } else { - self.error = {{ _e("Cannot load %(url)s", url="/frontend/settings") }}; + self.error = {{ _e("Cannot load %(url)s", url=url_prefix + "/frontend/settings") }}; self.loading = false; } }; settingsRequest.onerror = function() { - self.error = {{ _e("Cannot load %(url)s", url="/frontend/settings") }}; + self.error = {{ _e("Cannot load %(url)s", url=url_prefix + "/frontend/settings") }}; self.loading = false; }; langsRequest.onerror = function() { - self.error = {{ _e("Cannot load %(url)s", url="/languages") }}; + self.error = {{ _e("Cannot load %(url)s", url=url_prefix + "/languages") }}; self.loading = false; }; @@ -284,7 +284,7 @@ document.addEventListener('DOMContentLoaded', function(){ }; request.onerror = function() { - self.error = {{ _e("Cannot load %(url)s", url="/translate") }}; + self.error = {{ _e("Cannot load %(url)s", url=url_prefix + "/translate") }}; self.loadingTranslation = false; }; @@ -354,7 +354,7 @@ document.addEventListener('DOMContentLoaded', function(){ }; request.onerror = function() { - self.error = {{ _e("Cannot load %(url)s", url="/suggest") }}; + self.error = {{ _e("Cannot load %(url)s", url=url_prefix + "/suggest") }}; self.loadingTranslation = false; }; @@ -443,7 +443,7 @@ document.addEventListener('DOMContentLoaded', function(){ } translateFileRequest.onerror = function() { - const message = {{ _e("Cannot load %(url)s", url="/translate_file") }}; + const message = {{ _e("Cannot load %(url)s", url=url_prefix + "/translate_file") }}; self.error = message; self.loadingFileTranslation = false; self.inputFile = false; @@ -497,7 +497,7 @@ function handleLangsResponse(self, response) { self.handleInput(new Event('none')) } } else { - self.error = {{ _e("Cannot load %(url)s", url="/languages") }}; + self.error = {{ _e("Cannot load %(url)s", url=url_prefix + "/languages") }}; } self.loading = false; diff --git a/libretranslate/templates/index.html b/libretranslate/templates/index.html index 2ad0fee..e288cec 100644 --- a/libretranslate/templates/index.html +++ b/libretranslate/templates/index.html @@ -60,7 +60,7 @@