Repository: searx/searx

Issue:
/translations.js slows down Searx.
This commit https://github.com/asciimoo/searx/commit/4ca0d8cb0fd6c0e6b1301a6e8577aea6d928e9dc adds a new URL to serve a non static javascript file.

The script is loaded in the ```<head>``` section of the HTML page: https://github.com/asciimoo/searx/blob/4ca0d8cb0fd6c0e6b1301a6e8577aea6d928e9dc/searx/templates/oscar/base.html#L13

It takes usually at least 100ms to download (5% of 2 seconds), sometimes more, and since it is in the ```<head>``` section, the browser waits until the URL is downloaded and the content parsed. The file is reloaded each time since the user can change the locale.

You can see that in the devtools of a browser, or using curl:
```
curl     --write-out "%{http_code},%{time_total},%{time_connect},%{time_appconnect},%{time_starttransfer}\n"     --silent     --output /dev/null     "https://searx.be/translations.js"
```

It slows down Searx page load.

### solution 1: remove translations.js
* remove ```translations.js```
* add an additional attribute ```data-could-not-load``` to the ```script``` element:
https://github.com/asciimoo/searx/blob/4ca0d8cb0fd6c0e6b1301a6e8577aea6d928e9dc/searx/templates/oscar/base.html#L101-L103
* load the value from this file: 
https://github.com/asciimoo/searx/blob/4ca0d8cb0fd6c0e6b1301a6e8577aea6d928e9dc/searx/static/themes/oscar/js/searx_src/01_init.js#L26-L29

This solution is good for now because there is only one string to translate (in the ```oscar``` theme).
If there are more than one translation, a JSON structure can be serialized:
```html
<script src="searx.min.js" ... data-i18n="{ 'could_not_load': 'could not load data!' }" />
```

---

Side note: the ```simple``` theme already does something similar (see no_item_found):
* https://github.com/asciimoo/searx/blob/c41db5f1ba9984a916261535a9227fadb897f4bf/searx/static/themes/simple/js/searx_head/00_init.js#L28-L36 
* https://github.com/asciimoo/searx/blob/c41db5f1ba9984a916261535a9227fadb897f4bf/searx/templates/simple/base.html#L23-L29

### solution 2: ```translations.<:locale>.js```
Instead of one dynamic file, there is one per locale. The HTTP headers make sure the browser keeps the files in the cache. 
This solution leak the user locale in the reverse proxy logs.


Discussion:
Do you have exact numbers on how much it slows down searx? I measured it and it responds below 10ms.
Side note: There is another issue with the solution: currently the text isn't extracted to `messages.pot` by pybabel.
> Do you have exact numbers on how much it slows down searx? I measured it and it responds below 10ms.

* Flask answers quickly according to the ```server-timing``` HTTP header (between 5 and 15ms).
* From my network connection (4G connection): Firefox and Chrome says the request duration is ~70ms without extensions, ~100ms with my extensions.
* From ```check.searx.space``` to ```https://a.searx.space/translations.js``` (same host provider, curl): 80ms on the first request, ~25ms after.
* From ```searx.space``` to ```https://a.searx.space/translations.js``` (different host provider, curl): 491ms on the first request, ~32ms after.

[EDIT] the curl response times is most probably misleading since the URL is downloaded using an already existing HTTP/2 connection in the normal use case (the browser is already connected to the HTTPS server the download the HTTP page).

YMMV.

Okay, 70-100ms is noticeable indeed. I like the 2. solution you suggested, caching can speed up this a lot.

Resolving patch:
diff --git a/searx/webapp.py b/searx/webapp.py
--- a/searx/webapp.py
+++ b/searx/webapp.py
@@ -362,6 +362,15 @@ def image_proxify(url):
                             urlencode(dict(url=url.encode(), h=h)))
 
 
+def get_translations():
+    return {
+        # when overpass AJAX request fails (on a map result)
+        'could_not_load': gettext('could not load data'),
+        # when there is autocompletion
+        'no_item_found': gettext('No item found')
+    }
+
+
 def render(template_name, override_theme=None, **kwargs):
     disabled_engines = request.preferences.engines.get_disabled()
 
@@ -421,6 +430,8 @@ def render(template_name, override_theme=None, **kwargs):
 
     kwargs['brand'] = brand
 
+    kwargs['translations'] = json.dumps(get_translations(), separators=(',', ':'))
+
     kwargs['scripts'] = set()
     kwargs['endpoint'] = 'results' if 'q' in kwargs else request.endpoint
     for plugin in request.user_plugins:
@@ -1084,14 +1095,6 @@ def config():
     })
 
 
-@app.route('/translations.js')
-def js_translations():
-    return render(
-        'translations.js.tpl',
-        override_theme='__common__',
-    ), {'Content-Type': 'text/javascript; charset=UTF-8'}
-
-
 @app.errorhandler(404)
 def page_not_found(e):
     return render('404.html'), 404


Test patch: