From f4d4274b5a97d1f46e8a67d3c86541410ba9393f Mon Sep 17 00:00:00 2001 From: nune <145225213+gigirassy@users.noreply.github.com> Date: Wed, 26 Mar 2025 16:32:01 -0400 Subject: [PATCH 01/66] add blitzw.in instance --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ff82812..f503e2b 100644 --- a/README.md +++ b/README.md @@ -427,6 +427,7 @@ This is a list of public LibreTranslate instances, some require an API key. If y | ----------------------------------------------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------- | | [libretranslate.com](https://libretranslate.com) | :heavy_check_mark: | [ [Get API Key](https://portal.libretranslate.com) ] [ [Service Status](https://status.libretranslate.com/) ] | | [translate.flossboxin.org.in](https://translate.flossboxin.org.in/) | | [ [Contact/eMail](mailto:dev@flossboxin.org.in) ] | +| [lt.blitzw.in](https://lt.blitzw.in/) | | hosted by blitzw.in. uses an open source javascript-based captcha to fight bots! | ## TOR/i2p Mirrors From ae4a6ebfe65af0dc11aebfd568ff6b7a8d63dbe8 Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Wed, 26 Mar 2025 16:47:32 -0400 Subject: [PATCH 02/66] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f503e2b..fdf58bd 100644 --- a/README.md +++ b/README.md @@ -427,7 +427,7 @@ This is a list of public LibreTranslate instances, some require an API key. If y | ----------------------------------------------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------- | | [libretranslate.com](https://libretranslate.com) | :heavy_check_mark: | [ [Get API Key](https://portal.libretranslate.com) ] [ [Service Status](https://status.libretranslate.com/) ] | | [translate.flossboxin.org.in](https://translate.flossboxin.org.in/) | | [ [Contact/eMail](mailto:dev@flossboxin.org.in) ] | -| [lt.blitzw.in](https://lt.blitzw.in/) | | hosted by blitzw.in. uses an open source javascript-based captcha to fight bots! | +| [lt.blitzw.in](https://lt.blitzw.in/) | | | ## TOR/i2p Mirrors From c8f154561e5e2896d6097c3c738f2a372abf557a Mon Sep 17 00:00:00 2001 From: Ohirok Date: Fri, 28 Mar 2025 08:50:52 +0100 Subject: [PATCH 03/66] Translated using Weblate (Ukrainian) Translation: LibreTranslate/App Translate-URL: https://hosted.weblate.org/projects/libretranslate/app/uk/ --- .../locales/uk/LC_MESSAGES/messages.po | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/libretranslate/locales/uk/LC_MESSAGES/messages.po b/libretranslate/locales/uk/LC_MESSAGES/messages.po index 753fe73..37eca76 100644 --- a/libretranslate/locales/uk/LC_MESSAGES/messages.po +++ b/libretranslate/locales/uk/LC_MESSAGES/messages.po @@ -9,8 +9,8 @@ msgstr "" "Project-Id-Version: LibreTranslate 1.3.9\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2024-10-16 23:47+0200\n" -"PO-Revision-Date: 2024-10-26 12:15+0000\n" -"Last-Translator: Bezruchenko Simon \n" +"PO-Revision-Date: 2025-03-28 10:20+0000\n" +"Last-Translator: Ohirok \n" "Language-Team: Ukrainian \n" "Language: uk\n" @@ -19,7 +19,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -"X-Generator: Weblate 5.8.2-dev\n" +"X-Generator: Weblate 5.11-dev\n" "Generated-By: Babel 2.16.0\n" #: libretranslate/app.py:80 @@ -44,7 +44,7 @@ msgstr "Неправильний API ключ" #: libretranslate/app.py:324 msgid "Please contact the server operator to get an API key" -msgstr "Зв'яжіться з оператором сервера, щоб отримати API ключ" +msgstr "Зв'яжіться із оператором сервера, щоб отримати API ключ" #: libretranslate/app.py:326 #, python-format @@ -589,7 +589,7 @@ msgstr "зв'язатися з оператором сервера." #: libretranslate/templates/index.html:9 libretranslate/templates/index.html:27 #: libretranslate/templates/index.html:338 msgid "Free and Open Source Machine Translation API" -msgstr "Безкоштовний API машинного перекладу з відкритим вихідним кодом" +msgstr "Безплатний API машинного перекладу з відкритим сирцевим кодом" #: libretranslate/templates/index.html:10 #: libretranslate/templates/index.html:31 @@ -597,9 +597,9 @@ msgid "" "Free and Open Source Machine Translation API. Free to download, offline " "capable and easy to setup. Run your own API server in just a few minutes." msgstr "" -"Безкоштовний API машинного перекладу з відкритим вихідним кодом. " -"Безкоштовне завантаження, можливість роботи в офлайн режимі та простота " -"налаштування. Запустіть власний API сервер всього за кілька хвилин." +"Безплатний API машинного перекладу з відкритим сирцевим кодом. Безплатне " +"завантаження, можливість роботи в офлайн режимі та простота налаштування. " +"Запустіть власний API сервер всього за кілька хвилин." #: libretranslate/templates/index.html:11 msgid "translation" @@ -716,12 +716,12 @@ msgstr "Відповідь" #: libretranslate/templates/index.html:317 msgid "Open Source Machine Translation API" -msgstr "API машинного перекладу з відкритим вихідним кодом" +msgstr "API машинного перекладу з відкритим сирцевим кодом" #: libretranslate/templates/index.html:318 msgid "Free to download. Offline Capable. Easy to Setup." msgstr "" -"Безкоштовне завантаження. Можливість роботи в офлайн режимі. Простота " +"Безплвтне завантаження. Можливість роботи в офлайн режимі. Простота " "налаштування." #: libretranslate/templates/index.html:337 @@ -735,12 +735,12 @@ msgstr "Ліцензія:" #: libretranslate/templates/index.html:345 #, python-format msgid "Made with %(heart)s by %(contributors)s and powered by %(engine)s" -msgstr "Зроблено з %(heart)s %(contributors)s та працює на базі %(engine)s" +msgstr "Зроблено з %(heart)s %(contributors)s та працює на основі %(engine)s" #: libretranslate/templates/index.html:345 #, python-format msgid "%(libretranslate)s Contributors" -msgstr "Спільнотою %(libretranslate)s" +msgstr "спільнотою %(libretranslate)s" #~ msgid "multipart/form-data" #~ msgstr "мультипарт/форм-дані" From 6d43dfc5044b998fd9139248959a39d0ff36d65e Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Fri, 28 Mar 2025 12:28:08 -0400 Subject: [PATCH 04/66] Limiter func key with api key --- libretranslate/app.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libretranslate/app.py b/libretranslate/app.py index 0952290..b66a702 100644 --- a/libretranslate/app.py +++ b/libretranslate/app.py @@ -256,9 +256,18 @@ 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(): + ak = get_req_api_key() + return ak if ak else get_remote_address() + return func + else: + return get_remote_address limiter = Limiter( - key_func=get_remote_address, + key_func=get_limits_key_func(), default_limits=get_routes_limits( args, api_keys_db ), From ebbba3e4f6670ce7984f55cbd1c0dc0e62bd6c68 Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Fri, 28 Mar 2025 14:24:26 -0400 Subject: [PATCH 05/66] Update lexilang --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 6b22172..0e403f2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,7 @@ dependencies = [ "waitress ==2.1.2", "expiringdict ==1.2.2", "langdetect==1.0.9", - "lexilang==1.0.4", + "lexilang==1.0.6", "morfessor ==2.0.6", "appdirs ==1.4.4", "APScheduler ==3.9.1", From 75093e525fb0638b5d64781f902317d1e14e4a70 Mon Sep 17 00:00:00 2001 From: Manuela Silva Date: Sat, 29 Mar 2025 13:01:54 +0100 Subject: [PATCH 06/66] Translated using Weblate (Portuguese) Translation: LibreTranslate/App Translate-URL: https://hosted.weblate.org/projects/libretranslate/app/pt/ --- .../locales/pt/LC_MESSAGES/messages.po | 115 +++++++++--------- 1 file changed, 57 insertions(+), 58 deletions(-) diff --git a/libretranslate/locales/pt/LC_MESSAGES/messages.po b/libretranslate/locales/pt/LC_MESSAGES/messages.po index 7641f1a..bfac128 100644 --- a/libretranslate/locales/pt/LC_MESSAGES/messages.po +++ b/libretranslate/locales/pt/LC_MESSAGES/messages.po @@ -9,8 +9,8 @@ msgstr "" "Project-Id-Version: LibreTranslate 1.3.9\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2024-10-16 23:47+0200\n" -"PO-Revision-Date: 2025-02-01 14:01+0000\n" -"Last-Translator: Bruno Fragoso \n" +"PO-Revision-Date: 2025-03-30 13:01+0000\n" +"Last-Translator: Manuela Silva \n" "Language-Team: Portuguese \n" "Language: pt\n" @@ -18,7 +18,7 @@ msgstr "" "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.10-dev\n" +"X-Generator: Weblate 5.11-dev\n" "Generated-By: Babel 2.16.0\n" #: libretranslate/app.py:80 @@ -27,7 +27,7 @@ msgstr "Formato JSON inválido" #: libretranslate/app.py:180 libretranslate/templates/app.js.template:467 msgid "Auto Detect" -msgstr "Deteção automática" +msgstr "Deteção Automática" #: libretranslate/app.py:273 msgid "Unauthorized" @@ -35,7 +35,7 @@ msgstr "Não autorizado" #: libretranslate/app.py:291 msgid "Too many request limits violations" -msgstr "Muitas violações do limite de requisições" +msgstr "Muitas violações do limite de pedidos" #: libretranslate/app.py:298 msgid "Invalid API key" @@ -43,7 +43,7 @@ msgstr "Chave de API inválida" #: libretranslate/app.py:324 msgid "Please contact the server operator to get an API key" -msgstr "Entre em contacto com o operador do servidor para obter uma chave API" +msgstr "Por favor, contacte o operador do servidor para obter uma chave API" #: libretranslate/app.py:326 #, python-format @@ -52,7 +52,7 @@ msgstr "Visite %(url)s para obter uma chave API" #: libretranslate/app.py:373 msgid "Slowdown:" -msgstr "Devagar:" +msgstr "Abrandar:" #: libretranslate/app.py:606 libretranslate/app.py:608 #: libretranslate/app.py:610 libretranslate/app.py:819 @@ -67,12 +67,12 @@ msgstr "Pedido inválido: parâmetro %(name)s em falta" #: libretranslate/app.py:615 #, python-format msgid "Invalid request: %(name)s parameter is not a number" -msgstr "Requisição inválida: o parâmetro %(name)s não é um número" +msgstr "Pedido inválido: o parâmetro %(name)s não é um número" #: libretranslate/app.py:618 #, python-format msgid "Invalid request: %(name)s parameter must be <= %(value)s" -msgstr "Requisição inválida: o parâmetro %(name)s deve ser <= %(value)s" +msgstr "Pedido inválida: o parâmetro %(name)s deve ser <= %(value)s" #: libretranslate/app.py:635 libretranslate/app.py:645 #, python-format @@ -88,7 +88,7 @@ msgstr "%(lang)s não é suportado" #: libretranslate/app.py:671 #, python-format msgid "%(format)s format is not supported" -msgstr "%(format)s formato não é suportado" +msgstr "Formato %(format)s não é suportado" #: libretranslate/app.py:680 libretranslate/app.py:704 #, python-format @@ -96,8 +96,8 @@ msgid "" "%(tname)s (%(tcode)s) is not available as a target language from " "%(sname)s (%(scode)s)" msgstr "" -"%(tname)s (%(tcode)s) não está disponível como uma linguagem alvo de " -"%(sname)s (%(scode)s)" +"%(tname)s (%(tcode)s) não está disponível como idioma de destino de %(sname)" +"s (%(scode)s)" #: libretranslate/app.py:724 #, python-format @@ -106,23 +106,23 @@ msgstr "Não é possível traduzir o texto: %(text)s" #: libretranslate/app.py:811 libretranslate/app.py:872 msgid "Files translation are disabled on this server." -msgstr "A tradução de arquivos está desativada neste servidor." +msgstr "A tradução de ficheiros está desativada neste servidor." #: libretranslate/app.py:826 msgid "Invalid request: empty file" -msgstr "Pedido inválido: arquivo vazio" +msgstr "Pedido inválido: ficheiro vazio" #: libretranslate/app.py:829 msgid "Invalid request: file format not supported" -msgstr "Pedido inválido: formato de arquivo não suportado" +msgstr "Pedido inválido: formato de ficheiro não suportado" #: libretranslate/app.py:880 msgid "Invalid filename" -msgstr "Nome de arquivo inválido" +msgstr "Nome de ficheiro inválido" #: libretranslate/app.py:1122 msgid "Suggestions are disabled on this server." -msgstr "Sugestões estão desativadas neste servidor." +msgstr "As sugestões estão desativadas neste servidor." #: libretranslate/locales/.langs.py:1 msgid "English" @@ -262,7 +262,7 @@ msgstr "Polonês" #: libretranslate/locales/.langs.py:35 msgid "Portuguese" -msgstr "Português" +msgstr "Português (Portugal)" #: libretranslate/locales/.langs.py:36 msgid "Romanian" @@ -322,7 +322,7 @@ msgstr "Vietnamita" #: libretranslate/locales/.swag.py:1 msgid "Retrieve list of supported languages" -msgstr "Lista de idiomas suportados" +msgstr "Obter lista de idiomas suportados" #: libretranslate/locales/.swag.py:2 msgid "List of languages" @@ -342,7 +342,7 @@ msgstr "Texto traduzido" #: libretranslate/locales/.swag.py:6 msgid "Invalid request" -msgstr "Requisição inválida" +msgstr "Pedido inválido" #: libretranslate/locales/.swag.py:7 msgid "Translation error" @@ -350,7 +350,7 @@ msgstr "Erro ao traduzir" #: libretranslate/locales/.swag.py:8 msgid "Slow down" -msgstr "Devagar" +msgstr "Abrandar" #: libretranslate/locales/.swag.py:9 msgid "Banned" @@ -366,11 +366,11 @@ msgstr "Texto(s) para traduzir" #: libretranslate/locales/.swag.py:12 msgid "Source language code" -msgstr "Código da linguagem de origem" +msgstr "Código do idioma fonte" #: libretranslate/locales/.swag.py:13 msgid "Target language code" -msgstr "Código do idioma alvo" +msgstr "Código do idioma de destino" #: libretranslate/locales/.swag.py:14 msgid "text" @@ -412,11 +412,11 @@ msgstr "Ficheiro a traduzir" #: libretranslate/locales/.swag.py:22 msgid "Detect the language of a single text" -msgstr "Detectar a linguagem de um único texto" +msgstr "Detetar o idioma de um único texto" #: libretranslate/locales/.swag.py:23 msgid "Detections" -msgstr "Detecções" +msgstr "Deteções" #: libretranslate/locales/.swag.py:24 msgid "Detection error" @@ -424,15 +424,15 @@ msgstr "Erro de deteção" #: libretranslate/locales/.swag.py:25 msgid "Text to detect" -msgstr "Texto para detectar" +msgstr "Texto para detetar" #: libretranslate/locales/.swag.py:26 msgid "Retrieve frontend specific settings" -msgstr "Recupere configurações específicas do frontend" +msgstr "Obter configurações específicas do Frontend" #: libretranslate/locales/.swag.py:27 msgid "frontend settings" -msgstr "configurações de frontend" +msgstr "configurações do frontend" #: libretranslate/locales/.swag.py:28 msgid "frontend" @@ -440,7 +440,7 @@ msgstr "frontend" #: libretranslate/locales/.swag.py:29 msgid "Submit a suggestion to improve a translation" -msgstr "Envie uma sugestão para melhorar uma tradução" +msgstr "Submeter uma sugestão para melhorar uma tradução" #: libretranslate/locales/.swag.py:30 msgid "Success" @@ -468,11 +468,11 @@ msgstr "Idioma da tradução sugerida" #: libretranslate/locales/.swag.py:36 msgid "feedback" -msgstr "retorno" +msgstr "feedback" #: libretranslate/locales/.swag.py:37 msgid "Language code" -msgstr "Código de linguagem" +msgstr "Código do idioma" #: libretranslate/locales/.swag.py:38 msgid "Human-readable language name (in English)" @@ -480,7 +480,7 @@ msgstr "Nome do idioma legível para humanos (em inglês)" #: libretranslate/locales/.swag.py:39 msgid "Supported target language codes" -msgstr "Códigos de idioma alvo suportados" +msgstr "Códigos do idioma de destino suportados" #: libretranslate/locales/.swag.py:40 msgid "Translated text(s)" @@ -492,11 +492,11 @@ msgstr "Mensagem de erro" #: libretranslate/locales/.swag.py:42 msgid "Reason for slow down" -msgstr "Motivo da lentidão" +msgstr "Motivo por abrandar" #: libretranslate/locales/.swag.py:43 msgid "Translated file url" -msgstr "Url do arquivo traduzido" +msgstr "Url do ficheiro traduzido" #: libretranslate/locales/.swag.py:44 msgid "Confidence value" @@ -504,15 +504,15 @@ msgstr "Valor de confiança" #: libretranslate/locales/.swag.py:45 msgid "Character input limit for this language (-1 indicates no limit)" -msgstr "Limite de entrada de caracteres para esta língua (-1 indica sem limite)" +msgstr "Limite da entrada de carateres para este idioma (-1 indica sem limite)" #: libretranslate/locales/.swag.py:46 msgid "Frontend translation timeout" -msgstr "Tempo de tradução do frontend" +msgstr "Tempo de tradução do Frontend" #: libretranslate/locales/.swag.py:47 msgid "Whether the API key database is enabled." -msgstr "Se o banco de dados de chave API está ativado." +msgstr "Se a base de dados da chave API está ativada." #: libretranslate/locales/.swag.py:48 msgid "Whether an API key is required." @@ -520,7 +520,7 @@ msgstr "Se uma chave API é necessária." #: libretranslate/locales/.swag.py:49 msgid "Whether submitting suggestions is enabled." -msgstr "Se enviar sugestões está ativado." +msgstr "Se submeter sugestões está ativado." #: libretranslate/locales/.swag.py:50 msgid "Supported files format" @@ -528,7 +528,7 @@ msgstr "Formatos de ficheiros suportados" #: libretranslate/locales/.swag.py:51 msgid "Whether submission was successful" -msgstr "Se a submissão foi bem sucedida" +msgstr "Se a submissão foi bem-sucedida" #: libretranslate/templates/app.js.template:31 #: libretranslate/templates/app.js.template:294 @@ -545,7 +545,7 @@ msgstr "Copiar texto" #: libretranslate/templates/app.js.template:487 #, python-format msgid "Cannot load %(url)s" -msgstr "Não foi possível carregar %(url)s" +msgstr "Não é possível carregar %(url)s" #: libretranslate/templates/app.js.template:272 #: libretranslate/templates/app.js.template:342 @@ -563,8 +563,7 @@ msgid "" "Thanks for your correction. Note the suggestion will not take effect " "right away." msgstr "" -"Obrigado por sua correção. Note que a sugestão não terá efeito " -"imediatamente." +"Obrigado pela sua correção. Note que a sugestão não terá efeito de imediato." #: libretranslate/templates/app.js.template:463 msgid "No languages available. Did you install the models correctly?" @@ -573,11 +572,11 @@ msgstr "Não há idiomas disponíveis. Instalou os modelos corretamente?" #: libretranslate/templates/app.js.template:530 #, python-format msgid "Type in your API Key. If you need an API key, %(instructions)s" -msgstr "Digite sua chave API. Se precisar de uma chave API, %(instructions)s" +msgstr "Digite a sua chave API. Se precisar de uma chave API, %(instructions)s" #: libretranslate/templates/app.js.template:530 msgid "press the \"Get API Key\" link." -msgstr "pressione o link \"Obter Chave API\"." +msgstr "clique na hiperligação \"Obter Chave API\"." #: libretranslate/templates/app.js.template:530 msgid "contact the server operator." @@ -586,7 +585,7 @@ msgstr "contacte o operador do servidor." #: libretranslate/templates/index.html:9 libretranslate/templates/index.html:27 #: libretranslate/templates/index.html:338 msgid "Free and Open Source Machine Translation API" -msgstr "API de tradução em máquina gratuita e de código aberto" +msgstr "API de Tradução Automática Gratuita e de Código Aberto" #: libretranslate/templates/index.html:10 #: libretranslate/templates/index.html:31 @@ -594,9 +593,9 @@ msgid "" "Free and Open Source Machine Translation API. Free to download, offline " "capable and easy to setup. Run your own API server in just a few minutes." msgstr "" -"API de tradução em máquina gratuita e de código aberto. Grátis para descarregar, " -"off-line e fácil de configurar. Execute seu próprio servidor API em " -"apenas alguns minutos." +"API de Tradução Automática Gratuita e de Código Aberto. Grátis para " +"transferir, ''off-line'' e fácil de configurar. Execute o seu próprio " +"servidor API em apenas alguns minutos." #: libretranslate/templates/index.html:11 msgid "translation" @@ -636,19 +635,19 @@ msgstr "Alternar o modo escuro/claro" #: libretranslate/templates/index.html:159 msgid "Dismiss" -msgstr "Dispensar" +msgstr "Ignorar" #: libretranslate/templates/index.html:173 msgid "Translation API" -msgstr "API de tradução" +msgstr "API de Tradução" #: libretranslate/templates/index.html:177 msgid "Translate Text" -msgstr "Traduzir texto" +msgstr "Traduzir Texto" #: libretranslate/templates/index.html:181 msgid "Translate Files" -msgstr "Traduzir ficheiros" +msgstr "Traduzir Ficheiros" #: libretranslate/templates/index.html:187 msgid "Translate from" @@ -656,7 +655,7 @@ msgstr "Traduzir de" #: libretranslate/templates/index.html:197 msgid "Swap source and target languages" -msgstr "Inverter linguagens de origem e destino" +msgstr "Inverter idiomas fonte e de destino" #: libretranslate/templates/index.html:200 msgid "Translate into" @@ -701,7 +700,7 @@ msgstr "Traduzir" #: libretranslate/templates/index.html:278 #: libretranslate/templates/index.html:322 msgid "Download" -msgstr "Descarregar" +msgstr "Transferir" #: libretranslate/templates/index.html:297 msgid "Request" @@ -713,11 +712,11 @@ msgstr "Resposta" #: libretranslate/templates/index.html:317 msgid "Open Source Machine Translation API" -msgstr "API de tradução em máquina de código aberto" +msgstr "API de Tradução Automática Gratuita e de Código Aberto" #: libretranslate/templates/index.html:318 msgid "Free to download. Offline Capable. Easy to Setup." -msgstr "Grátis para descarregar. Funciona Offline. Fácil de configurar." +msgstr "Grátis para transferir. Funciona Off-line. Fácil de configurar." #: libretranslate/templates/index.html:337 msgid "LibreTranslate" @@ -730,12 +729,12 @@ msgstr "Licença:" #: libretranslate/templates/index.html:345 #, python-format msgid "Made with %(heart)s by %(contributors)s and powered by %(engine)s" -msgstr "Feito com %(heart)s por %(contributors)s e alimentado por %(engine)s" +msgstr "Criado com %(heart)s por %(contributors)s e alimentado por %(engine)s" #: libretranslate/templates/index.html:345 #, python-format msgid "%(libretranslate)s Contributors" -msgstr "Contribuintes %(libretranslate)s" +msgstr "Colaboradores %(libretranslate)s" #~ msgid "multipart/form-data" #~ msgstr "multipart/form-data" From 2dc443ea03e3ee2f1ce580cb35efe558a9d3ff81 Mon Sep 17 00:00:00 2001 From: Stefan McKinnon Edwards Date: Tue, 1 Apr 2025 21:20:59 +0200 Subject: [PATCH 07/66] Translated using Weblate (Danish) Translation: LibreTranslate/App Translate-URL: https://hosted.weblate.org/projects/libretranslate/app/da/ --- .../locales/da/LC_MESSAGES/messages.po | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/libretranslate/locales/da/LC_MESSAGES/messages.po b/libretranslate/locales/da/LC_MESSAGES/messages.po index 820e833..a23b750 100644 --- a/libretranslate/locales/da/LC_MESSAGES/messages.po +++ b/libretranslate/locales/da/LC_MESSAGES/messages.po @@ -9,14 +9,16 @@ msgstr "" "Project-Id-Version: LibreTranslate 1.3.9\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2024-10-16 23:47+0200\n" -"PO-Revision-Date: 2024-06-09 17:09+0000\n" -"Last-Translator: Luna \n" -"Language-Team: Danish \n" +"PO-Revision-Date: 2025-04-02 01:39+0000\n" +"Last-Translator: Stefan McKinnon Edwards \n" +"Language-Team: Danish \n" "Language: da\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.11-dev\n" "Generated-By: Babel 2.16.0\n" #: libretranslate/app.py:80 @@ -33,7 +35,7 @@ msgstr "Uautoriseret" #: libretranslate/app.py:291 msgid "Too many request limits violations" -msgstr "For mange overtrædelser af anmodningsbegrænsninger" +msgstr "For mange anmodninger" #: libretranslate/app.py:298 msgid "Invalid API key" @@ -50,7 +52,7 @@ msgstr "Besøg %(url)s for at få en API-nøgle" #: libretranslate/app.py:373 msgid "Slowdown:" -msgstr "Nedsættelse:" +msgstr "For mange forespørgsler:" #: libretranslate/app.py:606 libretranslate/app.py:608 #: libretranslate/app.py:610 libretranslate/app.py:819 @@ -60,25 +62,23 @@ msgstr "Nedsættelse:" #: libretranslate/app.py:1143 #, python-format msgid "Invalid request: missing %(name)s parameter" -msgstr "Ugyldig anmodning: manglende %(name)s-parameter" +msgstr "Ugyldig forespørgsel: manglende %(name)s-parameter" #: libretranslate/app.py:615 #, python-format msgid "Invalid request: %(name)s parameter is not a number" -msgstr "Ugyldig anmodning: %(name)s parameter er ikke et nummer" +msgstr "Ugyldig forespørgsel: %(name)s parameter er ikke et nummer" #: libretranslate/app.py:618 #, python-format msgid "Invalid request: %(name)s parameter must be <= %(value)s" -msgstr "" -"Ugyldig anmodning: %(name)s parameter skal være <= 1 1 1 1 " -"%(value)s" +msgstr "Ugyldig forespørgsel: %(name)s parameter skal være <= %(value)s" #: libretranslate/app.py:635 libretranslate/app.py:645 #, python-format msgid "Invalid request: request (%(size)s) exceeds text limit (%(limit)s)" msgstr "" -"Ugyldig anmodning: anmodningen (%(size)s) overskrider tekstgrænsen " +"Ugyldig forespørgsel: forespørgslen (%(size)s) overskrider tekstgrænsen " "(%(limit)s)" #: libretranslate/app.py:660 libretranslate/app.py:665 @@ -112,11 +112,11 @@ msgstr "Oversættelse af filer er deaktiveret på denne server." #: libretranslate/app.py:826 msgid "Invalid request: empty file" -msgstr "Ugyldig anmodning: tom fil" +msgstr "Ugyldig forespørgsel: tom fil" #: libretranslate/app.py:829 msgid "Invalid request: file format not supported" -msgstr "Ugyldig anmodning: filformat understøttes ikke" +msgstr "Ugyldig forespørgsel: filformat understøttes ikke" #: libretranslate/app.py:880 msgid "Invalid filename" @@ -344,7 +344,7 @@ msgstr "Oversat tekst" #: libretranslate/locales/.swag.py:6 msgid "Invalid request" -msgstr "Ugyldig anmodning" +msgstr "Ugyldig forespørgsel" #: libretranslate/locales/.swag.py:7 msgid "Translation error" From ecebc94f606fff0767b16db9a38b7cfa9af72454 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Farr=C3=A9?= Date: Fri, 4 Apr 2025 19:38:16 +0200 Subject: [PATCH 08/66] Translated using Weblate (Catalan) Translation: LibreTranslate/App Translate-URL: https://hosted.weblate.org/projects/libretranslate/app/ca/ --- .../locales/ca/LC_MESSAGES/messages.po | 117 +++++++++--------- 1 file changed, 59 insertions(+), 58 deletions(-) diff --git a/libretranslate/locales/ca/LC_MESSAGES/messages.po b/libretranslate/locales/ca/LC_MESSAGES/messages.po index 6c30d48..b7cddc5 100644 --- a/libretranslate/locales/ca/LC_MESSAGES/messages.po +++ b/libretranslate/locales/ca/LC_MESSAGES/messages.po @@ -9,8 +9,8 @@ msgstr "" "Project-Id-Version: LibreTranslate 1.3.12\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2024-10-16 23:47+0200\n" -"PO-Revision-Date: 2024-11-29 04:07+0000\n" -"Last-Translator: Quentin PAGÈS \n" +"PO-Revision-Date: 2025-04-04 17:51+0000\n" +"Last-Translator: Ivan Farré \n" "Language-Team: Catalan \n" "Language: ca\n" @@ -18,7 +18,7 @@ msgstr "" "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.9-dev\n" +"X-Generator: Weblate 5.11-dev\n" "Generated-By: Babel 2.16.0\n" #: libretranslate/app.py:80 @@ -130,7 +130,7 @@ msgstr "Els suggeriments estan deshabilitats en aquest servidor." #: libretranslate/locales/.langs.py:1 msgid "English" -msgstr "anglès" +msgstr "Anglès" #: libretranslate/locales/.langs.py:2 msgid "Albanian" @@ -138,11 +138,11 @@ msgstr "Albanès" #: libretranslate/locales/.langs.py:3 msgid "Arabic" -msgstr "àrab" +msgstr "Àrab" #: libretranslate/locales/.langs.py:4 msgid "Azerbaijani" -msgstr "àzeri" +msgstr "Àzeri" #: libretranslate/locales/.langs.py:5 msgid "Basque" @@ -162,7 +162,7 @@ msgstr "Català" #: libretranslate/locales/.langs.py:9 msgid "Chinese" -msgstr "xinès" +msgstr "Xinès" #: libretranslate/locales/.langs.py:10 msgid "Chinese (traditional)" @@ -170,19 +170,19 @@ msgstr "Xinès (tradicional)" #: libretranslate/locales/.langs.py:11 msgid "Czech" -msgstr "txec" +msgstr "Txec" #: libretranslate/locales/.langs.py:12 msgid "Danish" -msgstr "danès" +msgstr "Danès" #: libretranslate/locales/.langs.py:13 msgid "Dutch" -msgstr "holandès" +msgstr "Holandès" #: libretranslate/locales/.langs.py:14 msgid "Esperanto" -msgstr "esperanto" +msgstr "Esperanto" #: libretranslate/locales/.langs.py:15 msgid "Estonian" @@ -190,11 +190,11 @@ msgstr "Estonià" #: libretranslate/locales/.langs.py:16 msgid "Finnish" -msgstr "finès" +msgstr "Finès" #: libretranslate/locales/.langs.py:17 msgid "French" -msgstr "francès" +msgstr "Francès" #: libretranslate/locales/.langs.py:18 msgid "Galician" @@ -202,43 +202,43 @@ msgstr "Gallec" #: libretranslate/locales/.langs.py:19 msgid "German" -msgstr "alemany" +msgstr "Alemany" #: libretranslate/locales/.langs.py:20 msgid "Greek" -msgstr "grec" +msgstr "Grec" #: libretranslate/locales/.langs.py:21 msgid "Hebrew" -msgstr "hebreu" +msgstr "Hebreu" #: libretranslate/locales/.langs.py:22 msgid "Hindi" -msgstr "hindi" +msgstr "Hindi" #: libretranslate/locales/.langs.py:23 msgid "Hungarian" -msgstr "hongarès" +msgstr "Hongarès" #: libretranslate/locales/.langs.py:24 msgid "Indonesian" -msgstr "indonesi" +msgstr "Indonesi" #: libretranslate/locales/.langs.py:25 msgid "Irish" -msgstr "irlandès" +msgstr "Irlandès" #: libretranslate/locales/.langs.py:26 msgid "Italian" -msgstr "italià" +msgstr "Italià" #: libretranslate/locales/.langs.py:27 msgid "Japanese" -msgstr "japonès" +msgstr "Japonès" #: libretranslate/locales/.langs.py:28 msgid "Korean" -msgstr "coreà" +msgstr "Coreà" #: libretranslate/locales/.langs.py:29 msgid "Latvian" @@ -258,15 +258,15 @@ msgstr "Noruec" #: libretranslate/locales/.langs.py:33 msgid "Persian" -msgstr "persa" +msgstr "Persa" #: libretranslate/locales/.langs.py:34 msgid "Polish" -msgstr "polonès" +msgstr "Polonès" #: libretranslate/locales/.langs.py:35 msgid "Portuguese" -msgstr "portuguès" +msgstr "Portuguès" #: libretranslate/locales/.langs.py:36 msgid "Romanian" @@ -274,11 +274,11 @@ msgstr "Romanès" #: libretranslate/locales/.langs.py:37 msgid "Russian" -msgstr "rus" +msgstr "Rus" #: libretranslate/locales/.langs.py:38 msgid "Slovak" -msgstr "eslovac" +msgstr "Eslovac" #: libretranslate/locales/.langs.py:39 msgid "Slovenian" @@ -286,11 +286,11 @@ msgstr "Eslovè" #: libretranslate/locales/.langs.py:40 msgid "Spanish" -msgstr "castellà" +msgstr "Castellà" #: libretranslate/locales/.langs.py:41 msgid "Swedish" -msgstr "suec" +msgstr "Suec" #: libretranslate/locales/.langs.py:42 msgid "Tagalog" @@ -302,11 +302,11 @@ msgstr "Tai" #: libretranslate/locales/.langs.py:44 msgid "Turkish" -msgstr "turc" +msgstr "Turc" #: libretranslate/locales/.langs.py:45 msgid "Ukranian" -msgstr "ucraïnès" +msgstr "Ucraïnès" #: libretranslate/locales/.langs.py:46 msgid "Urdu" @@ -404,7 +404,7 @@ msgstr "Clau API" #: libretranslate/locales/.swag.py:19 msgid "Translate file from a language to another" -msgstr "Tradueix el fitxer des d' un idioma a un altre" +msgstr "Tradueix el fitxer des d'un idioma a un altre" #: libretranslate/locales/.swag.py:20 msgid "Translated file" @@ -416,11 +416,11 @@ msgstr "Fitxer a traduir" #: libretranslate/locales/.swag.py:22 msgid "Detect the language of a single text" -msgstr "Detecta l' idioma d' un únic text" +msgstr "Detecta l'idioma d'un únic text" #: libretranslate/locales/.swag.py:23 msgid "Detections" -msgstr "Detecciós" +msgstr "Deteccions" #: libretranslate/locales/.swag.py:24 msgid "Detection error" @@ -432,15 +432,15 @@ msgstr "Text a detectar" #: libretranslate/locales/.swag.py:26 msgid "Retrieve frontend specific settings" -msgstr "Recupera els arranjaments específics del frontal" +msgstr "Recupereu la configuració específica de la interfície" #: libretranslate/locales/.swag.py:27 msgid "frontend settings" -msgstr "configuració del frontal" +msgstr "configuració de la interfície" #: libretranslate/locales/.swag.py:28 msgid "frontend" -msgstr "frontal" +msgstr "interfície" #: libretranslate/locales/.swag.py:29 msgid "Submit a suggestion to improve a translation" @@ -472,19 +472,19 @@ msgstr "Idioma de traducció suggerida" #: libretranslate/locales/.swag.py:36 msgid "feedback" -msgstr "reacció" +msgstr "comentaris" #: libretranslate/locales/.swag.py:37 msgid "Language code" -msgstr "Codi d' idioma" +msgstr "Codi d'idioma" #: libretranslate/locales/.swag.py:38 msgid "Human-readable language name (in English)" -msgstr "Nom de l' idioma llegible (en anglès)" +msgstr "Nom de l'idioma llegible (en anglès)" #: libretranslate/locales/.swag.py:39 msgid "Supported target language codes" -msgstr "Codis d' idioma de destí acceptats" +msgstr "Codis d'idioma de destí acceptats" #: libretranslate/locales/.swag.py:40 msgid "Translated text(s)" @@ -492,7 +492,7 @@ msgstr "Text traduït(s)" #: libretranslate/locales/.swag.py:41 msgid "Error message" -msgstr "Missatge d' error" +msgstr "Missatge d'error" #: libretranslate/locales/.swag.py:42 msgid "Reason for slow down" @@ -509,16 +509,16 @@ msgstr "Valor de confiança" #: libretranslate/locales/.swag.py:45 msgid "Character input limit for this language (-1 indicates no limit)" msgstr "" -"Límit d' entrada de caràcters per a aquest idioma (- 1 indica que no hi ha " +"Límit d'entrada de caràcters per a aquest idioma (- 1 indica que no hi ha " "límit)" #: libretranslate/locales/.swag.py:46 msgid "Frontend translation timeout" -msgstr "Expiració de la traducció del Frontal" +msgstr "Expiració de la traducció de la interfície" #: libretranslate/locales/.swag.py:47 msgid "Whether the API key database is enabled." -msgstr "Si la base de dades de claus de l' API està habilitada." +msgstr "Si la base de dades de claus de l'API està habilitada." #: libretranslate/locales/.swag.py:48 msgid "Whether an API key is required." @@ -526,7 +526,7 @@ msgstr "Si es requereix una clau API." #: libretranslate/locales/.swag.py:49 msgid "Whether submitting suggestions is enabled." -msgstr "Si s' han d' habilitar els suggeriments d' enviament." +msgstr "Si s'han d'habilitar els suggeriments d'enviament." #: libretranslate/locales/.swag.py:50 msgid "Supported files format" @@ -551,7 +551,7 @@ msgstr "Copia text" #: libretranslate/templates/app.js.template:487 #, python-format msgid "Cannot load %(url)s" -msgstr "No s' ha pogut carregar %(url)s" +msgstr "No s'ha pogut carregar %(url)s" #: libretranslate/templates/app.js.template:272 #: libretranslate/templates/app.js.template:342 @@ -562,7 +562,7 @@ msgstr "Error desconegut" #: libretranslate/templates/app.js.template:295 msgid "Copied" -msgstr "S' ha copiat" +msgstr "S'ha copiat" #: libretranslate/templates/app.js.template:339 msgid "" @@ -584,11 +584,11 @@ msgstr "" #: libretranslate/templates/app.js.template:530 msgid "press the \"Get API Key\" link." -msgstr "premeu l' enllaç \"Treta la clau de l' API.\"." +msgstr "premeu l'enllaç \"Obtén la clau de l'API\"." #: libretranslate/templates/app.js.template:530 msgid "contact the server operator." -msgstr "contacteu amb l' operador del servidor." +msgstr "contacteu amb l'operador del servidor." #: libretranslate/templates/index.html:9 #: libretranslate/templates/index.html:27 @@ -602,8 +602,9 @@ msgid "" "Free and Open Source Machine Translation API. Free to download, offline capable " "and easy to setup. Run your own API server in just a few minutes." msgstr "" -"API de traducció de la màquina lliure i oberta. Auto- màquina, fora de línia" -" capaç de configurar. Executa el vostre servidor API en només uns minuts." +"API de traducció automàtica gratuïta i de codi obert. Descàrrega gratuïta, " +"compatible fora de línia i fàcil de configurar. Executeu el vostre propi " +"servidor d'API en només uns minuts." #: libretranslate/templates/index.html:11 msgid "translation" @@ -627,11 +628,11 @@ msgstr "GitHub" #: libretranslate/templates/index.html:73 msgid "Set API Key" -msgstr "Estableix l' API Clau" +msgstr "Estableix la Clau API" #: libretranslate/templates/index.html:75 msgid "Change language" -msgstr "Canvia l' idioma" +msgstr "Canvia l'idioma" #: libretranslate/templates/index.html:81 msgid "Edit" @@ -720,15 +721,15 @@ msgstr "Resposta" #: libretranslate/templates/index.html:317 msgid "Open Source Machine Translation API" -msgstr "Obre l' API de traducció de la màquina d' origen" +msgstr "Obre l'API de traducció de la màquina d'origen" #: libretranslate/templates/index.html:318 msgid "Free to download. Offline Capable. Easy to Setup." -msgstr "Ha acabat. Capable fora de línia. Fàcil de configurar." +msgstr "Descàrrega gratuïta. Capacitat fora de línia. Fàcil de configurar." #: libretranslate/templates/index.html:337 msgid "LibreTranslate" -msgstr "Librescue" +msgstr "LibreTranslate" #: libretranslate/templates/index.html:339 msgid "License:" From 3bcb32dcf857f58efce9e04c50123d1949c15662 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Farr=C3=A9?= Date: Fri, 4 Apr 2025 20:20:05 +0200 Subject: [PATCH 09/66] =?UTF-8?q?=F0=9F=8C=8F=20i18n:=20Improve=20Catalan?= =?UTF-8?q?=20translation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libretranslate/locales/ca/meta.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libretranslate/locales/ca/meta.json b/libretranslate/locales/ca/meta.json index acbb6a6..3eb289f 100644 --- a/libretranslate/locales/ca/meta.json +++ b/libretranslate/locales/ca/meta.json @@ -1,4 +1,4 @@ { "name": "Catalan", - "reviewed": false -} \ No newline at end of file + "reviewed": true +} From 4e86bfa991e7742feed62f4398120224f5fe95f5 Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Mon, 7 Apr 2025 23:28:34 -0400 Subject: [PATCH 10/66] Support for ISO 639-1 - 15924 codes --- VERSION | 2 +- libretranslate/app.py | 35 +++++++++++++++++++---------------- libretranslate/detect.py | 6 ++++-- libretranslate/language.py | 24 ++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 19 deletions(-) diff --git a/VERSION b/VERSION index 9f05f9f..bd8bf88 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.6.5 +1.7.0 diff --git a/libretranslate/app.py b/libretranslate/app.py index b66a702..a1570c3 100644 --- a/libretranslate/app.py +++ b/libretranslate/app.py @@ -22,7 +22,7 @@ from werkzeug.http import http_date from werkzeug.utils import secure_filename from libretranslate import flood, remove_translated_files, scheduler, secret, security, storage -from libretranslate.language import detect_languages, improve_translation_formatting +from libretranslate.language import model2iso, iso2model, detect_languages, improve_translation_formatting from libretranslate.locales import ( _, _lazy, @@ -499,7 +499,10 @@ def create_app(args): type: string description: Supported target language codes """ - return jsonify([{"code": l.code, "name": _lazy(l.name), "targets": language_pairs.get(l.code, [])} for l in languages]) + return jsonify([{"code": model2iso(l.code), + "name": _lazy(l.name), + "targets": model2iso(language_pairs.get(l.code, [])) + } for l in languages]) # Add cors @bp.after_request @@ -626,14 +629,14 @@ def create_app(args): if request.is_json: json = get_json_dict(request) q = json.get("q") - source_lang = json.get("source") - target_lang = json.get("target") + source_lang = iso2model(json.get("source")) + target_lang = iso2model(json.get("target")) text_format = json.get("format") num_alternatives = int(json.get("alternatives", 0)) else: q = request.values.get("q") - source_lang = request.values.get("source") - target_lang = request.values.get("target") + source_lang = iso2model(request.values.get("source")) + target_lang = iso2model(request.values.get("target")) text_format = request.values.get("format") num_alternatives = request.values.get("alternatives", 0) @@ -689,7 +692,7 @@ def create_app(args): candidate_langs = detect_languages(src_texts) detected_src_lang = candidate_langs[0] else: - detected_src_lang = {"confidence": 100.0, "language": source_lang} + detected_src_lang = {"confidence": 100.0, "language": model2iso(source_lang)} else: detected_src_lang = {"confidence": 0.0, "language": "en"} @@ -736,7 +739,7 @@ def create_app(args): result = {"translatedText": batch_results} if source_lang == "auto": - result["detectedLanguage"] = [detected_src_lang] * len(q) + result["detectedLanguage"] = [model2iso(detected_src_lang)] * len(q) if num_alternatives > 0: result["alternatives"] = batch_alternatives @@ -761,7 +764,7 @@ def create_app(args): result = {"translatedText": translated_text} if source_lang == "auto": - result["detectedLanguage"] = detected_src_lang + result["detectedLanguage"] = model2iso(detected_src_lang) if num_alternatives > 0: result["alternatives"] = alternatives @@ -857,8 +860,8 @@ def create_app(args): if args.disable_files_translation: abort(403, description=_("Files translation are disabled on this server.")) - source_lang = request.form.get("source") - target_lang = request.form.get("target") + source_lang = iso2model(request.form.get("source")) + target_lang = iso2model(request.form.get("target")) file = request.files['file'] char_limit = get_char_limit(args.char_limit, api_keys_db) @@ -1034,7 +1037,7 @@ def create_app(args): if not q: abort(400, description=_("Invalid request: missing %(name)s parameter", name='q')) - return jsonify(detect_languages(q)) + return jsonify(model2iso(detect_languages(q))) @bp.route("/frontend/settings") @limiter.exempt @@ -1180,13 +1183,13 @@ def create_app(args): json = get_json_dict(request) q = json.get("q") s = json.get("s") - source_lang = json.get("source") - target_lang = json.get("target") + source_lang = iso2model(json.get("source")) + target_lang = iso2model(json.get("target")) else: q = request.values.get("q") s = request.values.get("s") - source_lang = request.values.get("source") - target_lang = request.values.get("target") + source_lang = iso2model(request.values.get("source")) + target_lang = iso2model(request.values.get("target")) if not q: abort(400, description=_("Invalid request: missing %(name)s parameter", name='q')) diff --git a/libretranslate/detect.py b/libretranslate/detect.py index 7661227..023adba 100644 --- a/libretranslate/detect.py +++ b/libretranslate/detect.py @@ -21,9 +21,11 @@ def check_lang(langcodes, lang): def normalized_lang_code(lang): code = lang.lang - # Handle zh-cn - if code.startswith("zh"): + # Handle Chinese + if code == "zh-cn": code = "zh" + elif code == "zh-tw": + code = "zt" return code class Detector: diff --git a/libretranslate/language.py b/libretranslate/language.py index 0709cad..7383c74 100644 --- a/libretranslate/language.py +++ b/libretranslate/language.py @@ -6,6 +6,30 @@ from argostranslate import translate from libretranslate.detect import Detector __languages = None +aliases = { + 'pb': 'pt-BR', + 'zh': 'zh-Hans', + 'zt': 'zh-Hant', +} +rev_aliases = {v.lower(): k for k, v in aliases.items()} + +def iso2model(lang): + if not isinstance(lang, str): + return lang + + lang = lang.lower() + return rev_aliases.get(lang, lang) + +def model2iso(lang): + if isinstance(lang, dict) and 'language' in lang: + d = dict(lang) + d['language'] = model2iso(d['language']) + return d + elif isinstance(lang, list): + return [model2iso(l) for l in lang] + + lang = lang.lower() + return aliases.get(lang, lang) def load_languages(): global __languages From 29c9f39e8f87a6d5b96a37b89e5f68ec4d92b2f5 Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Tue, 8 Apr 2025 11:58:20 -0400 Subject: [PATCH 11/66] Fix ISO code aliasing in /translate --- libretranslate/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libretranslate/app.py b/libretranslate/app.py index a1570c3..fd3ec8c 100644 --- a/libretranslate/app.py +++ b/libretranslate/app.py @@ -692,7 +692,7 @@ def create_app(args): candidate_langs = detect_languages(src_texts) detected_src_lang = candidate_langs[0] else: - detected_src_lang = {"confidence": 100.0, "language": model2iso(source_lang)} + detected_src_lang = {"confidence": 100.0, "language": source_lang} else: detected_src_lang = {"confidence": 0.0, "language": "en"} From 182f6063f05d21d9ae27382eee645f45cda5c409 Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Tue, 8 Apr 2025 22:09:08 -0400 Subject: [PATCH 12/66] ISO lang code support for --load-only --- libretranslate/init.py | 2 ++ libretranslate/language.py | 3 +++ 2 files changed, 5 insertions(+) diff --git a/libretranslate/init.py b/libretranslate/init.py index 098cb20..0df8ba3 100644 --- a/libretranslate/init.py +++ b/libretranslate/init.py @@ -27,6 +27,8 @@ def check_and_install_models(force=False, load_only_lang_codes=None,update=False print("Found %s models" % len(available_packages)) if load_only_lang_codes is not None: # load_only_lang_codes: List[str] (codes) + load_only_lang_codes = libretranslate.language.iso2model(load_only_lang_codes) + # Ensure the user does not use any unavailable language code. unavailable_lang_codes = set(load_only_lang_codes) for pack in available_packages: diff --git a/libretranslate/language.py b/libretranslate/language.py index 7383c74..42f8866 100644 --- a/libretranslate/language.py +++ b/libretranslate/language.py @@ -14,6 +14,9 @@ aliases = { rev_aliases = {v.lower(): k for k, v in aliases.items()} def iso2model(lang): + if isinstance(lang, list): + return [iso2model(l) for l in lang] + if not isinstance(lang, str): return lang From f1aeee9016e03843dee0d20339fcd711d84440b9 Mon Sep 17 00:00:00 2001 From: ButterflyOfFire Date: Wed, 9 Apr 2025 16:19:44 +0200 Subject: [PATCH 13/66] Translated using Weblate (Kabyle) Translation: LibreTranslate/App Translate-URL: https://hosted.weblate.org/projects/libretranslate/app/kab/ --- libretranslate/locales/kab/LC_MESSAGES/messages.po | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libretranslate/locales/kab/LC_MESSAGES/messages.po b/libretranslate/locales/kab/LC_MESSAGES/messages.po index 270c613..2366985 100644 --- a/libretranslate/locales/kab/LC_MESSAGES/messages.po +++ b/libretranslate/locales/kab/LC_MESSAGES/messages.po @@ -9,7 +9,7 @@ msgstr "" "Project-Id-Version: LibreTranslate 1.3.9\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2024-10-16 23:47+0200\n" -"PO-Revision-Date: 2025-03-05 07:12+0000\n" +"PO-Revision-Date: 2025-04-09 19:20+0000\n" "Last-Translator: ButterflyOfFire \n" "Language-Team: Kabyle \n" @@ -18,7 +18,7 @@ msgstr "" "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.10.3-dev\n" +"X-Generator: Weblate 5.11-dev\n" "Generated-By: Babel 2.16.0\n" #: libretranslate/app.py:80 @@ -393,7 +393,7 @@ msgstr "" #: libretranslate/locales/.swag.py:17 msgid "Preferred number of alternative translations" -msgstr "" +msgstr "Amḍan-ik·im ufrin n tsuqilin timlellayin" #: libretranslate/locales/.swag.py:18 msgid "API key" From d1d950026966734645a7042bd5c6f3d6ed68d8ea Mon Sep 17 00:00:00 2001 From: Marc Riera Date: Fri, 11 Apr 2025 13:56:31 +0200 Subject: [PATCH 14/66] Translated using Weblate (Catalan) Translation: LibreTranslate/App Translate-URL: https://hosted.weblate.org/projects/libretranslate/app/ca/ --- .../locales/ca/LC_MESSAGES/messages.po | 90 ++++++++++--------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/libretranslate/locales/ca/LC_MESSAGES/messages.po b/libretranslate/locales/ca/LC_MESSAGES/messages.po index b7cddc5..c42744f 100644 --- a/libretranslate/locales/ca/LC_MESSAGES/messages.po +++ b/libretranslate/locales/ca/LC_MESSAGES/messages.po @@ -9,8 +9,8 @@ msgstr "" "Project-Id-Version: LibreTranslate 1.3.12\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2024-10-16 23:47+0200\n" -"PO-Revision-Date: 2025-04-04 17:51+0000\n" -"Last-Translator: Ivan Farré \n" +"PO-Revision-Date: 2025-04-11 12:43+0000\n" +"Last-Translator: Marc Riera \n" "Language-Team: Catalan \n" "Language: ca\n" @@ -126,7 +126,7 @@ msgstr "Nom de fitxer no vàlid" #: libretranslate/app.py:1122 msgid "Suggestions are disabled on this server." -msgstr "Els suggeriments estan deshabilitats en aquest servidor." +msgstr "Els suggeriments estan inhabilitats en aquest servidor." #: libretranslate/locales/.langs.py:1 msgid "English" @@ -326,15 +326,15 @@ msgstr "Vietnamita" #: libretranslate/locales/.swag.py:1 msgid "Retrieve list of supported languages" -msgstr "Recupera la llista d'idiomes compatibles" +msgstr "Recupera la llista de llengües admeses" #: libretranslate/locales/.swag.py:2 msgid "List of languages" -msgstr "Llista d'idiomes" +msgstr "Llista de llengües" #: libretranslate/locales/.swag.py:3 msgid "translate" -msgstr "traduir" +msgstr "traducció" #: libretranslate/locales/.swag.py:4 msgid "Translate text from a language to another" @@ -370,11 +370,11 @@ msgstr "Text(s) a traduir" #: libretranslate/locales/.swag.py:12 msgid "Source language code" -msgstr "Codi de l'idioma font" +msgstr "Codi de la llengua d'origen" #: libretranslate/locales/.swag.py:13 msgid "Target language code" -msgstr "Codi de l'idioma objectiu" +msgstr "Codi de la llengua de destinació" #: libretranslate/locales/.swag.py:14 msgid "text" @@ -390,9 +390,9 @@ msgid "" " * `text` - Plain text\n" " * `html` - HTML markup\n" msgstr "" -"Format del text del codi font:\n" -"* handheldtext text text text_ text pla\n" -"* htmlhtmlhtmlhtml - marca HTML\n" +"Format del text original:\n" +" * `text`: text sense format\n" +" * `html`: format HTML\n" #: libretranslate/locales/.swag.py:17 msgid "Preferred number of alternative translations" @@ -400,7 +400,7 @@ msgstr "Nombre preferit de traduccions alternatives" #: libretranslate/locales/.swag.py:18 msgid "API key" -msgstr "Clau API" +msgstr "Clau de l'API" #: libretranslate/locales/.swag.py:19 msgid "Translate file from a language to another" @@ -530,7 +530,7 @@ msgstr "Si s'han d'habilitar els suggeriments d'enviament." #: libretranslate/locales/.swag.py:50 msgid "Supported files format" -msgstr "Format de fitxers acceptats" +msgstr "Formats de fitxer acceptats" #: libretranslate/locales/.swag.py:51 msgid "Whether submission was successful" @@ -540,7 +540,7 @@ msgstr "Si la submissió ha estat correcta" #: libretranslate/templates/app.js.template:294 #: libretranslate/templates/app.js.template:298 msgid "Copy text" -msgstr "Copia text" +msgstr "Copia el text" #: libretranslate/templates/app.js.template:80 #: libretranslate/templates/app.js.template:86 @@ -569,32 +569,34 @@ msgid "" "Thanks for your correction. Note the suggestion will not take effect right " "away." msgstr "" -"Gràcies per la teva correcció. Noteu que el suggeriment no tindrà efecte " -"immediatament." +"Gràcies per la correcció. Tingueu en compte que el suggeriment no tindrà un " +"efecte immediat." #: libretranslate/templates/app.js.template:463 msgid "No languages available. Did you install the models correctly?" -msgstr "No hi ha idiomes disponibles. Has instal·lat correctament els models?" +msgstr "" +"No hi ha cap llengua disponible. Heu instal·lat correctament els models?" #: libretranslate/templates/app.js.template:530 #, python-format msgid "Type in your API Key. If you need an API key, %(instructions)s" msgstr "" -"Escriviu la vostra clau API. Si necessiteu una clau API, %(instructions)s" +"Escriviu la vostra clau de l'API. Si necessiteu una clau de l'API, " +"%(instructions)s" #: libretranslate/templates/app.js.template:530 msgid "press the \"Get API Key\" link." -msgstr "premeu l'enllaç \"Obtén la clau de l'API\"." +msgstr "premeu l'enllaç «Obtén una clau de l'API»." #: libretranslate/templates/app.js.template:530 msgid "contact the server operator." -msgstr "contacteu amb l'operador del servidor." +msgstr "poseu-vos en contacte amb l'operador del servidor." #: libretranslate/templates/index.html:9 #: libretranslate/templates/index.html:27 #: libretranslate/templates/index.html:338 msgid "Free and Open Source Machine Translation API" -msgstr "API de traducció de la màquina lliure i oberta" +msgstr "API de traducció automàtica lliure i oberta" #: libretranslate/templates/index.html:10 #: libretranslate/templates/index.html:31 @@ -602,9 +604,9 @@ msgid "" "Free and Open Source Machine Translation API. Free to download, offline capable " "and easy to setup. Run your own API server in just a few minutes." msgstr "" -"API de traducció automàtica gratuïta i de codi obert. Descàrrega gratuïta, " -"compatible fora de línia i fàcil de configurar. Executeu el vostre propi " -"servidor d'API en només uns minuts." +"API de traducció automàtica gratuïta i de codi obert. Baixa gratuïta, amb " +"possibilitat d'ús fora de línia i fàcil de configurar. Executeu el vostre " +"propi servidor d'API en només uns minuts." #: libretranslate/templates/index.html:11 msgid "translation" @@ -616,11 +618,11 @@ msgstr "api" #: libretranslate/templates/index.html:67 msgid "API Docs" -msgstr "API Docs" +msgstr "Documentació de l'API" #: libretranslate/templates/index.html:69 msgid "Get API Key" -msgstr "Obtén API Clau" +msgstr "Obtén una clau de l'API" #: libretranslate/templates/index.html:71 msgid "GitHub" @@ -628,11 +630,11 @@ msgstr "GitHub" #: libretranslate/templates/index.html:73 msgid "Set API Key" -msgstr "Estableix la Clau API" +msgstr "Defineix la clau de l'API" #: libretranslate/templates/index.html:75 msgid "Change language" -msgstr "Canvia l'idioma" +msgstr "Canvia de llengua" #: libretranslate/templates/index.html:81 msgid "Edit" @@ -640,7 +642,7 @@ msgstr "Edita" #: libretranslate/templates/index.html:83 msgid "Toggle dark/light mode" -msgstr "Commuta el mode fosc/ clar" +msgstr "Canvia entre els modes fosc i clar" #: libretranslate/templates/index.html:159 msgid "Dismiss" @@ -652,7 +654,7 @@ msgstr "API de traducció" #: libretranslate/templates/index.html:177 msgid "Translate Text" -msgstr "Tradueix el text" +msgstr "Tradueix text" #: libretranslate/templates/index.html:181 msgid "Translate Files" @@ -660,15 +662,15 @@ msgstr "Tradueix fitxers" #: libretranslate/templates/index.html:187 msgid "Translate from" -msgstr "Tradueix des de" +msgstr "Tradueix de" #: libretranslate/templates/index.html:197 msgid "Swap source and target languages" -msgstr "Intercanvia idiomes font i objectiu" +msgstr "Intercanvia les llengües d'origen i de destinació" #: libretranslate/templates/index.html:200 msgid "Translate into" -msgstr "Tradueix dins" +msgstr "Tradueix a" #: libretranslate/templates/index.html:212 msgid "Text to translate" @@ -676,15 +678,15 @@ msgstr "Text a traduir" #: libretranslate/templates/index.html:215 msgid "Delete text" -msgstr "Esborra text" +msgstr "Esborra el text" #: libretranslate/templates/index.html:228 msgid "Suggest translation" -msgstr "Suggereix traducció" +msgstr "Suggereix una traducció" #: libretranslate/templates/index.html:232 msgid "Cancel" -msgstr "Cancel· la" +msgstr "Cancel·la" #: libretranslate/templates/index.html:235 msgid "Send" @@ -692,7 +694,7 @@ msgstr "Envia" #: libretranslate/templates/index.html:251 msgid "Supported file formats:" -msgstr "Formats de fitxer acceptats:" +msgstr "Formats de fitxer admesos:" #: libretranslate/templates/index.html:255 msgid "File" @@ -700,7 +702,7 @@ msgstr "Fitxer" #: libretranslate/templates/index.html:270 msgid "Remove file" -msgstr "Elimina fitxer" +msgstr "Suprimeix el fitxer" #: libretranslate/templates/index.html:277 msgid "Translate" @@ -709,11 +711,11 @@ msgstr "Tradueix" #: libretranslate/templates/index.html:278 #: libretranslate/templates/index.html:322 msgid "Download" -msgstr "Descarrega" +msgstr "Baixa" #: libretranslate/templates/index.html:297 msgid "Request" -msgstr "Sol· licita" +msgstr "Sol·licitud" #: libretranslate/templates/index.html:302 msgid "Response" @@ -721,11 +723,11 @@ msgstr "Resposta" #: libretranslate/templates/index.html:317 msgid "Open Source Machine Translation API" -msgstr "Obre l'API de traducció de la màquina d'origen" +msgstr "API de traducció automàtica de codi obert" #: libretranslate/templates/index.html:318 msgid "Free to download. Offline Capable. Easy to Setup." -msgstr "Descàrrega gratuïta. Capacitat fora de línia. Fàcil de configurar." +msgstr "Baixada gratuïta. Possibilitat d'ús fora de línia. Fàcil de configurar." #: libretranslate/templates/index.html:337 msgid "LibreTranslate" @@ -738,12 +740,12 @@ msgstr "Llicència:" #: libretranslate/templates/index.html:345 #, python-format msgid "Made with %(heart)s by %(contributors)s and powered by %(engine)s" -msgstr "Fet amb %(heart)s per %(contributors)s i alimentat per %(engine)s" +msgstr "Fet amb %(heart)s pels %(contributors)s i amb tecnologia de %(engine)s" #: libretranslate/templates/index.html:345 #, python-format msgid "%(libretranslate)s Contributors" -msgstr "%(libretranslate)s Col· laboradors" +msgstr "col·laboradors de %(libretranslate)s" #~ msgid "Vietnamese" #~ msgstr "vietnamita" From a566d4556fd7649b1183279423dca1b91450c4a5 Mon Sep 17 00:00:00 2001 From: Marc Riera Date: Fri, 11 Apr 2025 14:56:13 +0200 Subject: [PATCH 15/66] Translated using Weblate (Catalan) Translation: LibreTranslate/App Translate-URL: https://hosted.weblate.org/projects/libretranslate/app/ca/ --- .../locales/ca/LC_MESSAGES/messages.po | 85 ++++++++++--------- 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/libretranslate/locales/ca/LC_MESSAGES/messages.po b/libretranslate/locales/ca/LC_MESSAGES/messages.po index c42744f..44afce2 100644 --- a/libretranslate/locales/ca/LC_MESSAGES/messages.po +++ b/libretranslate/locales/ca/LC_MESSAGES/messages.po @@ -9,7 +9,7 @@ msgstr "" "Project-Id-Version: LibreTranslate 1.3.12\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2024-10-16 23:47+0200\n" -"PO-Revision-Date: 2025-04-11 12:43+0000\n" +"PO-Revision-Date: 2025-04-11 15:57+0000\n" "Last-Translator: Marc Riera \n" "Language-Team: Catalan \n" @@ -23,7 +23,7 @@ msgstr "" #: libretranslate/app.py:80 msgid "Invalid JSON format" -msgstr "Format JSON invàlid" +msgstr "El format JSON no és vàlid" #: libretranslate/app.py:180 libretranslate/templates/app.js.template:467 msgid "Auto Detect" @@ -35,26 +35,26 @@ msgstr "No autoritzat" #: libretranslate/app.py:291 msgid "Too many request limits violations" -msgstr "Massa violacions de límits de la sol·licitud" +msgstr "Massa infraccions dels límits de sol·licituds" #: libretranslate/app.py:298 msgid "Invalid API key" -msgstr "Clau API invàlida" +msgstr "La clau de l'API no és vàlida" #: libretranslate/app.py:324 msgid "Please contact the server operator to get an API key" msgstr "" -"Si us plau, contacta amb l'administrador del servidor per demanar una clau " -"API" +"Poseu-vos en contacte amb l'operador del servidor per a obtenir una clau de " +"l'API" #: libretranslate/app.py:326 #, python-format msgid "Visit %(url)s to get an API key" -msgstr "Visita %(url)s per demanar una clau API" +msgstr "Visiteu %(url)s per a obtenir una clau de l'API" #: libretranslate/app.py:373 msgid "Slowdown:" -msgstr "Alenteix:" +msgstr "Reduïu el nombre de sol·licituds:" #: libretranslate/app.py:606 libretranslate/app.py:608 #: libretranslate/app.py:610 libretranslate/app.py:819 @@ -64,35 +64,36 @@ msgstr "Alenteix:" #: libretranslate/app.py:1143 #, python-format msgid "Invalid request: missing %(name)s parameter" -msgstr "Sol·licitud no vàlida: falta el paràmetre %(name)s" +msgstr "La sol·licitud no és vàlida: falta el paràmetre %(name)s" #: libretranslate/app.py:615 #, python-format msgid "Invalid request: %(name)s parameter is not a number" -msgstr "Petició no vàlida: %(name)s el paràmetre no és un número" +msgstr "La sol·licitud no és vàlida: el paràmetre %(name)s no és un nombre" #: libretranslate/app.py:618 #, python-format msgid "Invalid request: %(name)s parameter must be <= %(value)s" -msgstr "Petició no vàlida: %(name)s el paràmetre ha de ser <= %(value)s" +msgstr "" +"La sol·licitud no és vàlida: el paràmetre %(name)s ha de ser <= %(value)s" #: libretranslate/app.py:635 libretranslate/app.py:645 #, python-format msgid "Invalid request: request (%(size)s) exceeds text limit (%(limit)s)" msgstr "" -"Sol·licitud no vàlida: la sol·licitud (%(size)s) supera el límit de text " -"(%(limit)s)" +"La sol·licitud no és vàlida: la sol·licitud (%(size)s) supera el límit de " +"text (%(limit)s)" #: libretranslate/app.py:660 libretranslate/app.py:665 #: libretranslate/app.py:834 libretranslate/app.py:839 #, python-format msgid "%(lang)s is not supported" -msgstr "El %(lang)s no és compatible" +msgstr "No s'admet %(lang)s" #: libretranslate/app.py:671 #, python-format msgid "%(format)s format is not supported" -msgstr "El format %(format)s no està implementat" +msgstr "No s'admet el format %(format)s" #: libretranslate/app.py:680 libretranslate/app.py:704 #, python-format @@ -100,7 +101,7 @@ msgid "" "%(tname)s (%(tcode)s) is not available as a target language from %(sname)s " "(%(scode)s)" msgstr "" -"%(tname)s (%(tcode)s) no està disponible com a llengua de destí des de " +"%(tname)s (%(tcode)s) no està disponible com a llengua de destinació des de " "%(sname)s (%(scode)s)" #: libretranslate/app.py:724 @@ -110,15 +111,15 @@ msgstr "No es pot traduir el text: %(text)s" #: libretranslate/app.py:811 libretranslate/app.py:872 msgid "Files translation are disabled on this server." -msgstr "La traducció de fitxers està deshabilitada en aquest servidor." +msgstr "La traducció de fitxers està inhabilitada en aquest servidor." #: libretranslate/app.py:826 msgid "Invalid request: empty file" -msgstr "Sol·licitud no vàlida: fitxer buit" +msgstr "La sol·licitud no és vàlida: el fitxer és buit" #: libretranslate/app.py:829 msgid "Invalid request: file format not supported" -msgstr "Sol·licitud no vàlida: el format del fitxer no està implementat" +msgstr "La sol·licitud no és vàlida: no s'admet el format del fitxer" #: libretranslate/app.py:880 msgid "Invalid filename" @@ -338,7 +339,7 @@ msgstr "traducció" #: libretranslate/locales/.swag.py:4 msgid "Translate text from a language to another" -msgstr "Traduir text d'un idioma a un altre" +msgstr "Tradueix text d'una llengua a una altra" #: libretranslate/locales/.swag.py:5 libretranslate/templates/index.html:224 msgid "Translated text" @@ -346,7 +347,7 @@ msgstr "Text traduït" #: libretranslate/locales/.swag.py:6 msgid "Invalid request" -msgstr "Petició no vàlida" +msgstr "Sol·licitud no vàlida" #: libretranslate/locales/.swag.py:7 msgid "Translation error" @@ -354,7 +355,7 @@ msgstr "S'ha produït un error de traducció" #: libretranslate/locales/.swag.py:8 msgid "Slow down" -msgstr "Redueix" +msgstr "Reduïu el nombre de sol·licituds" #: libretranslate/locales/.swag.py:9 msgid "Banned" @@ -366,7 +367,7 @@ msgstr "Hola món!" #: libretranslate/locales/.swag.py:11 msgid "Text(s) to translate" -msgstr "Text(s) a traduir" +msgstr "Textos a traduir" #: libretranslate/locales/.swag.py:12 msgid "Source language code" @@ -404,7 +405,7 @@ msgstr "Clau de l'API" #: libretranslate/locales/.swag.py:19 msgid "Translate file from a language to another" -msgstr "Tradueix el fitxer des d'un idioma a un altre" +msgstr "Tradueix un fitxer d'una llengua a una altra" #: libretranslate/locales/.swag.py:20 msgid "Translated file" @@ -416,7 +417,7 @@ msgstr "Fitxer a traduir" #: libretranslate/locales/.swag.py:22 msgid "Detect the language of a single text" -msgstr "Detecta l'idioma d'un únic text" +msgstr "Detecta la llengua d'un únic text" #: libretranslate/locales/.swag.py:23 msgid "Detections" @@ -432,7 +433,7 @@ msgstr "Text a detectar" #: libretranslate/locales/.swag.py:26 msgid "Retrieve frontend specific settings" -msgstr "Recupereu la configuració específica de la interfície" +msgstr "Recupera la configuració específica de la interfície" #: libretranslate/locales/.swag.py:27 msgid "frontend settings" @@ -444,11 +445,11 @@ msgstr "interfície" #: libretranslate/locales/.swag.py:29 msgid "Submit a suggestion to improve a translation" -msgstr "Envia un suggeriment per millorar una traducció" +msgstr "Envia un suggeriment per a millorar una traducció" #: libretranslate/locales/.swag.py:30 msgid "Success" -msgstr "Èxit" +msgstr "Correcte" #: libretranslate/locales/.swag.py:31 msgid "Not authorized" @@ -464,11 +465,11 @@ msgstr "Traducció suggerida" #: libretranslate/locales/.swag.py:34 msgid "Language of original text" -msgstr "Idioma del text original" +msgstr "Llengua del text original" #: libretranslate/locales/.swag.py:35 msgid "Language of suggested translation" -msgstr "Idioma de traducció suggerida" +msgstr "Llengua de la traducció suggerida" #: libretranslate/locales/.swag.py:36 msgid "feedback" @@ -476,19 +477,19 @@ msgstr "comentaris" #: libretranslate/locales/.swag.py:37 msgid "Language code" -msgstr "Codi d'idioma" +msgstr "Codi de llengua" #: libretranslate/locales/.swag.py:38 msgid "Human-readable language name (in English)" -msgstr "Nom de l'idioma llegible (en anglès)" +msgstr "Nom de la llengua comprensible per humans (en anglès)" #: libretranslate/locales/.swag.py:39 msgid "Supported target language codes" -msgstr "Codis d'idioma de destí acceptats" +msgstr "Codis de les llengües de destinació acceptades" #: libretranslate/locales/.swag.py:40 msgid "Translated text(s)" -msgstr "Text traduït(s)" +msgstr "Textos traduïts" #: libretranslate/locales/.swag.py:41 msgid "Error message" @@ -496,11 +497,11 @@ msgstr "Missatge d'error" #: libretranslate/locales/.swag.py:42 msgid "Reason for slow down" -msgstr "Motiu per alentir- se" +msgstr "Motiu per a reduir el nombre de sol·licituds" #: libretranslate/locales/.swag.py:43 msgid "Translated file url" -msgstr "URL de fitxer traduït" +msgstr "URL del fitxer traduït" #: libretranslate/locales/.swag.py:44 msgid "Confidence value" @@ -509,24 +510,24 @@ msgstr "Valor de confiança" #: libretranslate/locales/.swag.py:45 msgid "Character input limit for this language (-1 indicates no limit)" msgstr "" -"Límit d'entrada de caràcters per a aquest idioma (- 1 indica que no hi ha " +"Límit d'entrada de caràcters per a aquesta llengua (-1 indica que no hi ha " "límit)" #: libretranslate/locales/.swag.py:46 msgid "Frontend translation timeout" -msgstr "Expiració de la traducció de la interfície" +msgstr "Temps d'espera màxim de traducció de la interfície" #: libretranslate/locales/.swag.py:47 msgid "Whether the API key database is enabled." -msgstr "Si la base de dades de claus de l'API està habilitada." +msgstr "Indica si la base de dades de claus de l'API està habilitada." #: libretranslate/locales/.swag.py:48 msgid "Whether an API key is required." -msgstr "Si es requereix una clau API." +msgstr "Indica si es requereix una clau de l'API." #: libretranslate/locales/.swag.py:49 msgid "Whether submitting suggestions is enabled." -msgstr "Si s'han d'habilitar els suggeriments d'enviament." +msgstr "Indica si l'enviament de suggeriments està habilitat." #: libretranslate/locales/.swag.py:50 msgid "Supported files format" @@ -534,7 +535,7 @@ msgstr "Formats de fitxer acceptats" #: libretranslate/locales/.swag.py:51 msgid "Whether submission was successful" -msgstr "Si la submissió ha estat correcta" +msgstr "Indica si l'enviament ha estat correcte" #: libretranslate/templates/app.js.template:31 #: libretranslate/templates/app.js.template:294 From 9f123e1bbbe136f94565ba74b5cb94e8babd0ca0 Mon Sep 17 00:00:00 2001 From: GiannosOB Date: Sat, 12 Apr 2025 00:00:23 +0200 Subject: [PATCH 16/66] Translated using Weblate (Greek) Translation: LibreTranslate/App Translate-URL: https://hosted.weblate.org/projects/libretranslate/app/el/ --- libretranslate/locales/el/LC_MESSAGES/messages.po | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libretranslate/locales/el/LC_MESSAGES/messages.po b/libretranslate/locales/el/LC_MESSAGES/messages.po index 07c86bc..bc42fac 100644 --- a/libretranslate/locales/el/LC_MESSAGES/messages.po +++ b/libretranslate/locales/el/LC_MESSAGES/messages.po @@ -9,14 +9,16 @@ msgstr "" "Project-Id-Version: LibreTranslate 1.3.9\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2024-10-16 23:47+0200\n" -"PO-Revision-Date: 2024-08-24 07:09+0000\n" -"Last-Translator: Nikos Merianos \n" -"Language-Team: Greek \n" +"PO-Revision-Date: 2025-04-12 08:53+0000\n" +"Last-Translator: GiannosOB \n" +"Language-Team: Greek \n" "Language: el\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.11-dev\n" "Generated-By: Babel 2.16.0\n" #: libretranslate/app.py:80 @@ -633,7 +635,7 @@ msgstr "Επεξεργασία επεξεργασίας" #: libretranslate/templates/index.html:83 msgid "Toggle dark/light mode" -msgstr "Toggle dark/light mode" +msgstr "Εναλλαγή σκοτεινής/φωτεινής λειτουργίας" #: libretranslate/templates/index.html:159 msgid "Dismiss" From 1d6338b199b4b53156b340ed94243195ec59fc34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Alves?= Date: Wed, 16 Apr 2025 16:09:32 +0100 Subject: [PATCH 17/66] Update Dockerfile #737 Fixes LibreTranslate/LibreTranslate#737 problem related with pytorch version declared in pyproject.toml dependency and venv pip install. --- docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 304d305..d1219ec 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -15,7 +15,7 @@ COPY . . # Install package from source code, compile translations RUN ./venv/bin/pip install Babel==2.12.1 && ./venv/bin/python scripts/compile_locales.py \ - && ./venv/bin/pip install torch==2.0.1 --extra-index-url https://download.pytorch.org/whl/cpu \ + && ./venv/bin/pip install torch==2.2.0 --extra-index-url https://download.pytorch.org/whl/cpu \ && ./venv/bin/pip install "numpy<2" \ && ./venv/bin/pip install . \ && ./venv/bin/pip cache purge From 6522182d4a9503b2f344640e1d3594aa6b8af77d Mon Sep 17 00:00:00 2001 From: roshan Date: Thu, 17 Apr 2025 09:30:34 +0900 Subject: [PATCH 18/66] Update Requirements: argos-translate-files srt support --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 0e403f2..e8b1d42 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,7 @@ dependencies = [ "appdirs ==1.4.4", "APScheduler ==3.9.1", "translatehtml ==1.5.2", - "argos-translate-files ==1.2.0", + "argos-translate-files ==1.3.0", "itsdangerous ==2.1.2", "Werkzeug ==2.3.8", "requests ==2.31.0", From f38dbd160d1a90323128c7f6fe62bd880745bc13 Mon Sep 17 00:00:00 2001 From: Przemek Date: Thu, 17 Apr 2025 11:28:44 +0200 Subject: [PATCH 19/66] Translated using Weblate (Polish) Translation: LibreTranslate/App Translate-URL: https://hosted.weblate.org/projects/libretranslate/app/pl/ --- .../locales/pl/LC_MESSAGES/messages.po | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/libretranslate/locales/pl/LC_MESSAGES/messages.po b/libretranslate/locales/pl/LC_MESSAGES/messages.po index 6e76919..7887cdd 100644 --- a/libretranslate/locales/pl/LC_MESSAGES/messages.po +++ b/libretranslate/locales/pl/LC_MESSAGES/messages.po @@ -9,14 +9,17 @@ msgstr "" "Project-Id-Version: LibreTranslate 1.3.9\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2024-10-16 23:47+0200\n" -"PO-Revision-Date: 2024-09-03 16:09+0000\n" -"Last-Translator: Michał Stankiewicz \n" -"Language-Team: Polish \n" +"PO-Revision-Date: 2025-04-17 09:53+0000\n" +"Last-Translator: Przemek \n" +"Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2);\n" +"X-Generator: Weblate 5.11.1-dev\n" "Generated-By: Babel 2.16.0\n" #: libretranslate/app.py:80 @@ -194,7 +197,7 @@ msgstr "Francuski" #: libretranslate/locales/.langs.py:18 msgid "Galician" -msgstr "Galicyjczyk" +msgstr "Galicyjski" #: libretranslate/locales/.langs.py:19 msgid "German" @@ -210,7 +213,7 @@ msgstr "Hebrajski" #: libretranslate/locales/.langs.py:22 msgid "Hindi" -msgstr "Hindi" +msgstr "Hinduski" #: libretranslate/locales/.langs.py:23 msgid "Hungarian" @@ -238,7 +241,7 @@ msgstr "Koreański" #: libretranslate/locales/.langs.py:29 msgid "Latvian" -msgstr "Łotwa" +msgstr "Łotewski" #: libretranslate/locales/.langs.py:30 msgid "Lithuanian" From da0890d60fb976a505a716a61eead93936d639c4 Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Fri, 18 Apr 2025 03:49:05 -0400 Subject: [PATCH 20/66] web driver check --- libretranslate/templates/app.js.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libretranslate/templates/app.js.template b/libretranslate/templates/app.js.template index e5e6739..0b68e7e 100644 --- a/libretranslate/templates/app.js.template +++ b/libretranslate/templates/app.js.template @@ -95,7 +95,7 @@ document.addEventListener('DOMContentLoaded', function(){ settingsRequest.send(); langsRequest.send(); - {% if api_secret %}self[_=String.fromCharCode,p=parseInt,_(p(211,6)+false+p(30,0x6))+_(169-57)+_(p(104,5)+p(301,0x5))+_(p(1,7)+false+p(145,0x7))+_(101)+_(46+false+53)+_(/*_(72)*/)+_(/*_(16)*/)+_(/*_(15)*/)+_(1938/**\/*//17)+_(p(14142,6)/**\/*//p(34,0x6))+_(46+70)] = {{ api_secret }}; {% endif %} + {% if api_secret %}self[_=String.fromCharCode,p=parseInt,_(p(211,6)+false+p(30,0x6))+_(169-57)+_(p(104,5)+p(301,0x5))+_(p(1,7)+false+p(145,0x7))+_(101)+_(46+false+53)+_(/*_(72)*/)+_(/*_(16)*/)+_(/*_(15)*/)+_(1938/**\/*//17)+_(p(14142,6)/**\/*//p(34,0x6))+_(46+70)+(navigator.webdriver?"t":"")] = {{ api_secret }}; {% endif %} }, updated: function(){ if (this.isSuggesting) return; From c76dbcaf0a3fa98d0213582911d2af3ad5f0ef77 Mon Sep 17 00:00:00 2001 From: Cengizhan Peker Date: Fri, 18 Apr 2025 10:35:19 +0200 Subject: [PATCH 21/66] Translated using Weblate (Spanish) Translation: LibreTranslate/App Translate-URL: https://hosted.weblate.org/projects/libretranslate/app/es/ --- libretranslate/locales/es/LC_MESSAGES/messages.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libretranslate/locales/es/LC_MESSAGES/messages.po b/libretranslate/locales/es/LC_MESSAGES/messages.po index e8a7c65..243850e 100644 --- a/libretranslate/locales/es/LC_MESSAGES/messages.po +++ b/libretranslate/locales/es/LC_MESSAGES/messages.po @@ -9,8 +9,8 @@ msgstr "" "Project-Id-Version: LibreTranslate 1.3.9\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2024-10-16 23:47+0200\n" -"PO-Revision-Date: 2024-11-12 22:23+0000\n" -"Last-Translator: gallegonovato \n" +"PO-Revision-Date: 2025-04-18 15:45+0000\n" +"Last-Translator: Cengizhan Peker \n" "Language-Team: Spanish \n" "Language: es\n" @@ -18,12 +18,12 @@ msgstr "" "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.9-dev\n" +"X-Generator: Weblate 5.11.1-dev\n" "Generated-By: Babel 2.16.0\n" #: libretranslate/app.py:80 msgid "Invalid JSON format" -msgstr "Formato JSON inválido" +msgstr "JSON inválido" #: libretranslate/app.py:180 libretranslate/templates/app.js.template:467 msgid "Auto Detect" From fc4f4be24fcf7710192e46e3858ffba622015224 Mon Sep 17 00:00:00 2001 From: LTSlw Date: Fri, 18 Apr 2025 17:01:24 +0200 Subject: [PATCH 22/66] Translated using Weblate (Chinese (Simplified Han script)) Translation: LibreTranslate/App Translate-URL: https://hosted.weblate.org/projects/libretranslate/app/zh_Hans/ --- .../locales/zh/LC_MESSAGES/messages.po | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/libretranslate/locales/zh/LC_MESSAGES/messages.po b/libretranslate/locales/zh/LC_MESSAGES/messages.po index 222d428..9afebeb 100644 --- a/libretranslate/locales/zh/LC_MESSAGES/messages.po +++ b/libretranslate/locales/zh/LC_MESSAGES/messages.po @@ -9,8 +9,8 @@ msgstr "" "Project-Id-Version: LibreTranslate 1.3.9\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2024-10-16 23:47+0200\n" -"PO-Revision-Date: 2025-01-22 05:16+0000\n" -"Last-Translator: Poesty Li \n" +"PO-Revision-Date: 2025-04-18 15:45+0000\n" +"Last-Translator: LTSlw \n" "Language-Team: Chinese (Simplified Han script) \n" "Language: zh\n" @@ -18,12 +18,12 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 5.10-dev\n" +"X-Generator: Weblate 5.11.1-dev\n" "Generated-By: Babel 2.16.0\n" #: libretranslate/app.py:80 msgid "Invalid JSON format" -msgstr "无效的 JSON 格式" +msgstr "JSON 格式无效" #: libretranslate/app.py:180 libretranslate/templates/app.js.template:467 msgid "Auto Detect" @@ -31,19 +31,20 @@ msgstr "自动检测" #: libretranslate/app.py:273 msgid "Unauthorized" -msgstr "未经授权" +msgstr "未授权" #: libretranslate/app.py:291 +#, fuzzy msgid "Too many request limits violations" msgstr "请求次数过多超过限制" #: libretranslate/app.py:298 msgid "Invalid API key" -msgstr "无效的 API 密钥" +msgstr "API 密钥无效" #: libretranslate/app.py:324 msgid "Please contact the server operator to get an API key" -msgstr "请联系管理员以获取 API 密钥" +msgstr "请联系管理员获取 API 密钥" #: libretranslate/app.py:326 #, python-format @@ -51,6 +52,7 @@ msgid "Visit %(url)s to get an API key" msgstr "访问 %(url)s 以获取 API 密钥" #: libretranslate/app.py:373 +#, fuzzy msgid "Slowdown:" msgstr "慢一点:" From f2268fe4d9b4c1349f3deac34d7218513a6866c8 Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Fri, 18 Apr 2025 12:21:16 -0400 Subject: [PATCH 23/66] Add fingerprinting mechanism --- README.md | 25 +++++++++++++------------ VERSION | 2 +- libretranslate/app.py | 8 ++++++++ libretranslate/default_values.py | 5 +++++ libretranslate/flood.py | 13 +++++++++++++ libretranslate/main.py | 6 ++++++ libretranslate/secret.py | 2 +- libretranslate/storage.py | 24 ++++++++++++++++++------ 8 files changed, 65 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index fdf58bd..d70c1c5 100644 --- a/README.md +++ b/README.md @@ -192,18 +192,19 @@ Arguments passed to the process or set via environment variables are split into ### Settings / Flags -| Argument | Description | Default Setting | Env. name | -| --------------------------- | ----------------------------------------------------------------------------------------------------------- | ---------------------------------- | ---------------------------- | -| --debug | Enable debug environment | `Disabled` | LT_DEBUG | -| --ssl | Whether to enable SSL | `Disabled` | LT_SSL | -| --api-keys | Enable API keys database for per-client rate limits when --req-limit is reached | `Don't use API keys` | LT_API_KEYS | -| --require-api-key-origin | Require use of an API key for programmatic access to the API, unless the request origin matches this domain | `No restrictions on domain origin` | LT_REQUIRE_API_KEY_ORIGIN | -| --require-api-key-secret | Require use of an API key for programmatic access to the API, unless the client also sends a secret match | `No secrets required` | LT_REQUIRE_API_KEY_SECRET | -| --suggestions | Allow user suggestions | `Disabled` | LT_SUGGESTIONS | -| --disable-files-translation | Disable files translation | `File translation allowed` | LT_DISABLE_FILES_TRANSLATION | -| --disable-web-ui | Disable web ui | `Web Ui enabled` | LT_DISABLE_WEB_UI | -| --update-models | Update language models at startup | `Only on if no models found` | LT_UPDATE_MODELS | -| --metrics | Enable the /metrics endpoint for exporting [Prometheus](https://prometheus.io/) usage metrics | `Disabled` | LT_METRICS | +| Argument | Description | Default Setting | Env. name | +| ----------------------------- | ----------------------------------------------------------------------------------------------------------- | ---------------------------------- | ------------------------------ | +| --debug | Enable debug environment | `Disabled` | LT_DEBUG | +| --ssl | Whether to enable SSL | `Disabled` | LT_SSL | +| --api-keys | Enable API keys database for per-client rate limits when --req-limit is reached | `Don't use API keys` | LT_API_KEYS | +| --require-api-key-origin | Require use of an API key for programmatic access to the API, unless the request origin matches this domain | `No restrictions on domain origin` | LT_REQUIRE_API_KEY_ORIGIN | +| --require-api-key-secret | Require use of an API key for programmatic access to the API, unless the client also sends a secret match | `No secrets required` | LT_REQUIRE_API_KEY_SECRET | +| --require-api-key-fingerprint | Require use of an API key for programmatic access to the API, unless the client also matches a fingerprint | `No fingerprinting required` | LT_REQUIRE_API_KEY_FINGERPRINT | +| --suggestions | Allow user suggestions | `Disabled` | LT_SUGGESTIONS | +| --disable-files-translation | Disable files translation | `File translation allowed` | LT_DISABLE_FILES_TRANSLATION | +| --disable-web-ui | Disable web ui | `Web Ui enabled` | LT_DISABLE_WEB_UI | +| --update-models | Update language models at startup | `Only on if no models found` | LT_UPDATE_MODELS | +| --metrics | Enable the /metrics endpoint for exporting [Prometheus](https://prometheus.io/) usage metrics | `Disabled` | LT_METRICS | ### Configuration Parameters diff --git a/VERSION b/VERSION index bd8bf88..943f9cb 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.7.0 +1.7.1 diff --git a/libretranslate/app.py b/libretranslate/app.py index fd3ec8c..3dae777 100644 --- a/libretranslate/app.py +++ b/libretranslate/app.py @@ -102,6 +102,9 @@ def get_remote_address(): return ip +def get_fingerprint(): + return request.headers.get("User-Agent", "") + "|" + request.headers.get("Cookie", "") + def get_req_limits(default_limit, api_keys_db, db_multiplier=1, multiplier=1): req_limit = default_limit @@ -348,12 +351,17 @@ def create_app(args): and not secret.secret_match(req_secret) ): need_key = True + if secret.secret_bogus_match(req_secret): abort(make_response(jsonify({ 'translatedText': secret.get_emoji(), 'alternatives': [], 'detectedLanguage': { 'confidence': 100, 'language': 'en' } }), 200)) + + if args.require_api_key_fingerprint: + if flood.fingerprint_mismatch(ip, get_fingerprint()): + need_key = True if need_key: description = _("Please contact the server operator to get an API key") diff --git a/libretranslate/default_values.py b/libretranslate/default_values.py index 2c79611..4da8e29 100644 --- a/libretranslate/default_values.py +++ b/libretranslate/default_values.py @@ -151,6 +151,11 @@ _default_options_objects = [ 'default_value': False, 'value_type': 'bool' }, + { + 'name': 'REQUIRE_API_KEY_FINGERPRINT', + 'default_value': False, + 'value_type': 'bool' + }, { 'name': 'SHARED_STORAGE', 'default_value': 'memory://', diff --git a/libretranslate/flood.py b/libretranslate/flood.py index 63cd392..3f87c9b 100644 --- a/libretranslate/flood.py +++ b/libretranslate/flood.py @@ -45,3 +45,16 @@ def is_banned(request_ip): # More than X offences? return active and s.get_hash_int("banned", request_ip) >= threshold + +def fingerprint_mismatch(request_ip, fingerprint): + if not isinstance(fingerprint, str) or fingerprint == "": + return True + + s = get_storage() + k = f"fingerprint:{request_ip}" + expected = s.get_str(k) + if expected == "": + s.set_str(k, fingerprint, ex=300) + return False + else: + return fingerprint != expected \ No newline at end of file diff --git a/libretranslate/main.py b/libretranslate/main.py index b6b6a03..61d7585 100644 --- a/libretranslate/main.py +++ b/libretranslate/main.py @@ -147,6 +147,12 @@ def get_args(): action="store_true", help="Require use of an API key for programmatic access to the API, unless the client also sends a secret match", ) + parser.add_argument( + "--require-api-key-fingerprint", + default=DEFARGS['REQUIRE_API_KEY_FINGERPRINT'], + action="store_true", + help="Require use of an API key for programmatic access to the API, unless the client also matches a fingerprint", + ) parser.add_argument( "--shared-storage", type=str, diff --git a/libretranslate/secret.py b/libretranslate/secret.py index c8f278a..fdf818d 100644 --- a/libretranslate/secret.py +++ b/libretranslate/secret.py @@ -108,7 +108,7 @@ def get_emoji(): return random.choice(["😂", "🤪", "😜", "🤣", "😹", "🐒", "🙈", "🤡", "🥸", "😆", "🥴", "🐸", "🐤", "🐒🙊", "👀", "💩", "🤯", "😛", "🤥", "👻"]) def setup(args): - if args.api_keys and args.require_api_key_secret: + if args.require_api_key_secret: s = get_storage() if not s.exists("secret_0"): diff --git a/libretranslate/storage.py b/libretranslate/storage.py index 46bd9c5..696f097 100644 --- a/libretranslate/storage.py +++ b/libretranslate/storage.py @@ -1,4 +1,5 @@ import redis +import time storage = None def get_storage(): @@ -18,7 +19,7 @@ class Storage: def get_int(self, key): raise Exception("not implemented") - def set_str(self, key, value): + def set_str(self, key, value, ex=None): raise Exception("not implemented") def get_str(self, key): raise Exception("not implemented") @@ -56,11 +57,22 @@ class MemoryStorage(Storage): def get_int(self, key): return int(self.store.get(key, 0)) - def set_str(self, key, value): - self.store[key] = value + def set_str(self, key, value, ex=None): + self.store[key] = { + 'value': value, + 'ex': time.time() + ex + } def get_str(self, key): - return str(self.store.get(key, "")) + d = self.store.get(key, {'value': '', 'ex': None}) + if d['ex'] is None: + return d['value'] + else: + if d['ex'] <= time.time(): + del self.store[key] + return '' + else: + return d['value'] def set_hash_int(self, ns, key, value): if ns not in self.store: @@ -123,8 +135,8 @@ class RedisStorage(Storage): else: return v - def set_str(self, key, value): - self.conn.set(key, value) + def set_str(self, key, value, ex=None): + self.conn.set(key, value, ex=ex) def get_str(self, key): v = self.conn.get(key) From d8f91210093a17eb7ce0446f567a548f721f87dd Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Fri, 18 Apr 2025 12:22:56 -0400 Subject: [PATCH 24/66] Tweak fingerprint --- libretranslate/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libretranslate/app.py b/libretranslate/app.py index 3dae777..b7e56a6 100644 --- a/libretranslate/app.py +++ b/libretranslate/app.py @@ -103,7 +103,7 @@ def get_remote_address(): return ip def get_fingerprint(): - return request.headers.get("User-Agent", "") + "|" + request.headers.get("Cookie", "") + return request.headers.get("User-Agent", "") + request.headers.get("Cookie", "") def get_req_limits(default_limit, api_keys_db, db_multiplier=1, multiplier=1): From e4eb96482f4bbc67e0f19cb88e23cd655bed9dc0 Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Fri, 18 Apr 2025 12:28:12 -0400 Subject: [PATCH 25/66] Fingerprint only if key missing --- libretranslate/app.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libretranslate/app.py b/libretranslate/app.py index b7e56a6..765af32 100644 --- a/libretranslate/app.py +++ b/libretranslate/app.py @@ -359,7 +359,8 @@ def create_app(args): 'detectedLanguage': { 'confidence': 100, 'language': 'en' } }), 200)) - if args.require_api_key_fingerprint: + if (args.require_api_key_fingerprint + and key_missing): if flood.fingerprint_mismatch(ip, get_fingerprint()): need_key = True From bdb9b6a22410f8306604103448210154e6e58740 Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Fri, 18 Apr 2025 14:41:12 -0400 Subject: [PATCH 26/66] Under attack mode --- README.md | 1 + libretranslate/app.py | 6 +++++- libretranslate/default_values.py | 5 +++++ libretranslate/main.py | 6 ++++++ libretranslate/templates/index.html | 29 +++++++++++++++++++---------- 5 files changed, 36 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index d70c1c5..f0b0e8c 100644 --- a/README.md +++ b/README.md @@ -200,6 +200,7 @@ Arguments passed to the process or set via environment variables are split into | --require-api-key-origin | Require use of an API key for programmatic access to the API, unless the request origin matches this domain | `No restrictions on domain origin` | LT_REQUIRE_API_KEY_ORIGIN | | --require-api-key-secret | Require use of an API key for programmatic access to the API, unless the client also sends a secret match | `No secrets required` | LT_REQUIRE_API_KEY_SECRET | | --require-api-key-fingerprint | Require use of an API key for programmatic access to the API, unless the client also matches a fingerprint | `No fingerprinting required` | LT_REQUIRE_API_KEY_FINGERPRINT | +| --under-attack | Enable under attack mode. When enabled, requests must be made with an API key | `Disabled` | LT_UNDER_ATTACK | | --suggestions | Allow user suggestions | `Disabled` | LT_SUGGESTIONS | | --disable-files-translation | Disable files translation | `File translation allowed` | LT_DISABLE_FILES_TRANSLATION | | --disable-web-ui | Disable web ui | `Web Ui enabled` | LT_DISABLE_WEB_UI | diff --git a/libretranslate/app.py b/libretranslate/app.py index 765af32..02bc865 100644 --- a/libretranslate/app.py +++ b/libretranslate/app.py @@ -364,6 +364,9 @@ def create_app(args): if flood.fingerprint_mismatch(ip, get_fingerprint()): need_key = True + if args.under_attack and key_missing: + need_key = True + if need_key: description = _("Please contact the server operator to get an API key") if args.get_api_key_link: @@ -441,7 +444,8 @@ def create_app(args): swagger_url=swagger_url, available_locales=sorted([{'code': l['code'], 'name': _lazy(l['name'])} for l in get_available_locales(not args.debug)], key=lambda s: s['name']), current_locale=get_locale(), - alternate_locales=get_alternate_locale_links() + alternate_locales=get_alternate_locale_links(), + under_attack=args.under_attack, )) if args.require_api_key_secret: diff --git a/libretranslate/default_values.py b/libretranslate/default_values.py index 4da8e29..3d2e3a8 100644 --- a/libretranslate/default_values.py +++ b/libretranslate/default_values.py @@ -151,6 +151,11 @@ _default_options_objects = [ 'default_value': False, 'value_type': 'bool' }, + { + 'name': 'UNDER_ATTACK', + 'default_value': False, + 'value_type': 'bool' + }, { 'name': 'REQUIRE_API_KEY_FINGERPRINT', 'default_value': False, diff --git a/libretranslate/main.py b/libretranslate/main.py index 61d7585..ea6eb3d 100644 --- a/libretranslate/main.py +++ b/libretranslate/main.py @@ -153,6 +153,12 @@ def get_args(): action="store_true", help="Require use of an API key for programmatic access to the API, unless the client also matches a fingerprint", ) + parser.add_argument( + "--under-attack", + default=DEFARGS['UNDER_ATTACK'], + action="store_true", + help="Enable under attack mode. When enabled, requests must be made with an API key", + ) parser.add_argument( "--shared-storage", type=str, diff --git a/libretranslate/templates/index.html b/libretranslate/templates/index.html index 66bf936..61f1e0d 100644 --- a/libretranslate/templates/index.html +++ b/libretranslate/templates/index.html @@ -150,18 +150,18 @@
-
-
-
- warning

[[ error ]]

-
- +
+
+
+ warning

[[ error ]]

+
+ +
-
-
+
@@ -170,6 +170,15 @@
+ {% if under_attack %} +
+
+
+ warning {{ _h("Due to bot abuse, translation requests are temporarily limited to users with a valid API key. Sorry for the inconvenience!") }}

+
+
+
+ {% endif %}

{{ _h("Translation API") }}

- @@ -220,7 +220,7 @@ - + @@ -232,7 +232,7 @@ - +