simjanos-dev / LinguaCafe

LinguaCafe is a self-hosted software that helps language learners read foreign languages.
https://simjanos-dev.github.io/LinguaCafeHome/
GNU General Public License v3.0
848 stars 26 forks source link

Language install. #209

Closed simjanos-dev closed 4 months ago

simjanos-dev commented 4 months ago

@sergiolaverde0

I've opened this issue, so we can communicate about the language install feature. I'll close this issue when the feature is finished.

I've tried to install korean and list installed languages with the python functions. It installed successfully (the terminal said it was already installed when I tried to install again), but when I listed the installed languages it returned an empty array.

I've also tried to use the list function before a fresh install. I had all the languages installed already, and it did return them.

I've changed this line:

lang = request.headers.get('lang')

To this:

lang = request.json.get('lang')

because Laravel's default HTTP library converts post data to json automatically, and other python functions were written in the same way as well. Can it stay like this, can you still test the python functions?

sergiolaverde0 commented 4 months ago

Yes, that was the small detail I mentioned you could change back, and you did. I should be able to test it anyways by writing the JSON by hand, and I can add Thai and Vietnamese without touching that line anyways.

Tomorrow I will check what was going on with the empty array though, I thought that was working fine when I tested.

simjanos-dev commented 4 months ago

I've tried to import Chinese text, but it also gave an error when it tried to load the model.

When I try to install Chinese despite the list returns empty, it prints this in the terminal, so I assume Chinese is actually installed.

...
...
2024-04-20 10:04:55 WARNING: Target directory /var/www/html/storage/app/model/packaging-24.0.dist-info already exists. Specify --upgrade to force replacement.
2024-04-20 10:04:55 WARNING: Target directory /var/www/html/storage/app/model/catalogue-2.0.10.dist-info already exists. Specify --upgrade to force replacement.
2024-04-20 10:04:55 WARNING: Target directory /var/www/html/storage/app/model/urllib3 already exists. Specify --upgrade to force replacement.
2024-04-20 10:04:55 WARNING: Target directory /var/www/html/storage/app/model/bin already exists. Specify --upgrade to force replacement.
2024-04-20 10:04:55 WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv

Since it seems installed, I've changed the loading path for the actually installed location to test it:

if language == 'chinese':
        global chinese_nlp
        if chinese_nlp == None:
            chinese_nlp = spacy.load("/var/www/html/storage/app/model/zh_core_web_sm/zh_core_web_sm-3.7.0", disable = ['ner', 'parser'])
            chinese_nlp.add_pipe("custom_sentence_splitter", first=True)
        doc = chinese_nlp(words)

When I tried to import a Chinese text, I got this error message:

2024-04-20 10:12:57 <frozen importlib._bootstrap>:914: ImportWarning: _ImportRedirect.find_spec() not found; falling back to find_module()
2024-04-20 10:12:57 Traceback (most recent call last):
2024-04-20 10:12:57   File "/usr/local/lib/python3.10/dist-packages/bottle.py", line 876, in _handle
2024-04-20 10:12:57     return route.call(**args)
2024-04-20 10:12:57   File "/usr/local/lib/python3.10/dist-packages/bottle.py", line 1759, in wrapper
2024-04-20 10:12:57     rv = callback(*a, **ka)
2024-04-20 10:12:57   File "/app/tokenizer.py", line 289, in tokenizer
2024-04-20 10:12:57     jsonWords = tokenizeText(rawText, language)
2024-04-20 10:12:57   File "/app/tokenizer.py", line 223, in tokenizeText
2024-04-20 10:12:57     doc = getTokenizerDoc(language, words)
2024-04-20 10:12:57   File "/app/tokenizer.py", line 98, in getTokenizerDoc
2024-04-20 10:12:57     chinese_nlp = spacy.load("/var/www/html/storage/app/model/zh_core_web_sm/zh_core_web_sm-3.7.0", disable = ['ner', 'parser'])
2024-04-20 10:12:57   File "/usr/local/lib/python3.10/dist-packages/spacy/__init__.py", line 51, in load
2024-04-20 10:12:57     return util.load_model(
2024-04-20 10:12:57   File "/usr/local/lib/python3.10/dist-packages/spacy/util.py", line 467, in load_model
2024-04-20 10:12:57     return load_model_from_path(Path(name), **kwargs)  # type: ignore[arg-type]
2024-04-20 10:12:57   File "/usr/local/lib/python3.10/dist-packages/spacy/util.py", line 547, in load_model_from_path
2024-04-20 10:12:57     return nlp.from_disk(model_path, exclude=exclude, overrides=overrides)
2024-04-20 10:12:57   File "/usr/local/lib/python3.10/dist-packages/spacy/language.py", line 2209, in from_disk
2024-04-20 10:12:57     util.from_disk(path, deserializers, exclude)  # type: ignore[arg-type]
2024-04-20 10:12:57   File "/usr/local/lib/python3.10/dist-packages/spacy/util.py", line 1390, in from_disk
2024-04-20 10:12:57     reader(path / key)
2024-04-20 10:12:57   File "/usr/local/lib/python3.10/dist-packages/spacy/language.py", line 2195, in <lambda>
2024-04-20 10:12:57     deserializers["tokenizer"] = lambda p: self.tokenizer.from_disk(  # type: ignore[union-attr]
2024-04-20 10:12:57   File "/usr/local/lib/python3.10/dist-packages/spacy/lang/zh/__init__.py", line 283, in from_disk
2024-04-20 10:12:57     util.from_disk(path, serializers, [])
2024-04-20 10:12:57   File "/usr/local/lib/python3.10/dist-packages/spacy/util.py", line 1390, in from_disk
2024-04-20 10:12:57     reader(path / key)
2024-04-20 10:12:57   File "/usr/local/lib/python3.10/dist-packages/spacy/lang/zh/__init__.py", line 280, in <lambda>
2024-04-20 10:12:57     "pkuseg_model": lambda p: load_pkuseg_model(p),
2024-04-20 10:12:57   File "/usr/local/lib/python3.10/dist-packages/spacy/lang/zh/__init__.py", line 257, in load_pkuseg_model
2024-04-20 10:12:57     raise ImportError(
2024-04-20 10:12:57 ImportError: spacy-pkuseg not installed. To use this model, install spacy-pkuseg with `pip install "spacy-pkuseg>=0.0.27,<0.1.0"` or `conda install -c conda-forge "spacy-pkuseg>=0.0.27,<0.1.0"`

Pkuseg is the Chinese dependency.

I'm not sure if I tried to use it correctly, I might have overlooked something.

sergiolaverde0 commented 4 months ago
2024-04-20 10:04:55 WARNING: Target directory /var/www/html/storage/app/model/catalogue-2.0.10.dist-info already exists. Specify --upgrade to force replacement.
2024-04-20 10:04:55 WARNING: Target directory /var/www/html/storage/app/model/urllib3 already exists. Specify --upgrade to force replacement.
2024-04-20 10:04:55 WARNING: Target directory /var/www/html/storage/app/model/bin already exists. Specify --upgrade to force replacement.
2024-04-20 10:04:55 WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv

Where are you getting this output from? When I test it on my local repo (no changes on that line yet) this is the log I get on the Python container when installing Korean and checking it is on the list:

linguacafe-python-service  | Listening on http://0.0.0.0:8678/
linguacafe-python-service  | Hit Ctrl-C to quit.
linguacafe-python-service  | 
linguacafe-python-service  | WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
linguacafe-python-service  | 172.24.0.1 - - [20/Apr/2024 12:36:01] "POST /models/install HTTP/1.1" 200 45
linguacafe-python-service  | 172.24.0.1 - - [20/Apr/2024 12:36:48] "GET /models/list HTTP/1.1" 200 10

Is there any way we can see what see the exact JSON that Laravel is sending to the Python container? Another interesting check is doing ' docker exec shand navigate to/var/www/html/storage/app/modelthen dols` to check if the folder for the language is actually there or not.

On the meantime I will change that line on my fork and test it handwriting the JSON to see if I can reproduce.

sergiolaverde0 commented 4 months ago

Can confirm I was able to install Korean, get it listed and confirm its directory exists using this JSON body: {"lang": "korean"}

simjanos-dev commented 4 months ago

Where are you getting this output from?

I get it right before your line that you wrote:

linguacafe-python-service | 172.24.0.1 - - [20/Apr/2024 12:36:01] "POST /models/install HTTP/1.1" 200 45

To be clear, the warnings are not error messages, they do not indicate that something is wrong, rather the opposite. I get those warnings if I try to install a language for a second time after I already installed it. I did this to check if the the list function has a problem, or if it actually didn't install. It seems like the install works, but I get an empty [] from the list function.

Can confirm I was able to install Korean, get it listed and confirm its directory exists using this JSON body: {"lang": "korean"}

I delete the models directory, and I'll try to test it again. I'll show the logs in a few minutes after it's done.

I don't think it affects it, but I use my usual dev environment, which does not copy the whole folder to the image, rather it just mounts it like it used to be before we had proper docker images.

sergiolaverde0 commented 4 months ago

Right, I think I know what is going on. the install is working fine, but listing the languages is returning the list on a format that Laravel does not expect. When I install several languages and list them I get this in the browser and Bruno gives me this:

[
  "korean",
  "russian",
  "chinese"
]

I suspect that is our issue.

simjanos-dev commented 4 months ago

I used the latest features/language-install branch to test, and the tool accessible on localhost:3000/dev to test it with the new functions.

(Http methods and post data names used here are for the laravel, not for the python server. For the python server the correct post data names and methods are being used. I'll rename my methods and post data names to make them the same later.)

Step 1: delete old folder Method: GET Url: /languages/installed/delete Response: Installed languages has been deleted successfully. Server log: 2024-04-20 15:01:35 172.19.0.4 - - [20/Apr/2024 13:01:35] "DELETE /models/remove HTTP/1.1" 200 35

The model directory did disappear. It works.

Step 2: install korean

Method: POST Url: /languages/install JSON POST Data: {"language": "korean"} Response: Language has been installed successfully. Server log: 2024-04-20 15:07:37 172.19.0.4 - - [20/Apr/2024 13:07:37] "POST /models/install HTTP/1.1" 200 45

The model folder got created and is is now 172MB.

Step 3: list languages

Method: GET Url: /languages/installed/list Response: An empty array with status code 200. Server log: 2024-04-20 15:09:51 172.19.0.4 - - [20/Apr/2024 13:09:51] "GET /models/list HTTP/1.1" 200 2

Here is the full server log in one block:

2024-04-20 13:52:20 Bottle v0.12.25 server starting up (using WSGIRefServer())...
2024-04-20 13:52:20 Listening on http://0.0.0.0:8678/
2024-04-20 13:52:20 Hit Ctrl-C to quit.
2024-04-20 13:52:20 
2024-04-20 14:59:03 WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
2024-04-20 14:59:04 172.19.0.4 - - [20/Apr/2024 12:59:04] "POST /models/install HTTP/1.1" 200 45
2024-04-20 15:01:35 172.19.0.4 - - [20/Apr/2024 13:01:35] "DELETE /models/remove HTTP/1.1" 200 35
2024-04-20 15:07:36 WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
2024-04-20 15:07:37 172.19.0.4 - - [20/Apr/2024 13:07:37] "POST /models/install HTTP/1.1" 200 45
2024-04-20 15:09:51 172.19.0.4 - - [20/Apr/2024 13:09:51] "GET /models/list HTTP/1.1" 200 2

{"lang": "korean"}

This is what laravel sends to the python server. I can test it somehow skipping laravel as well, but I don't think that's the issue, because the install seem to work, and the list requires no post data.

Right, I think I know what is going on. the install is working fine, but listing the languages is returning the list on a format that Laravel does not expect.

Do not think this is the issue, because I tested it with a print in the python list function before sending back the data, and that also was an empty array.

I'll download bruno.

simjanos-dev commented 4 months ago

bruno list

I've had the same result with bruno, this one went for the python server directly.

It is a really silly question, I'm only asking this because I forgot about this. Did you remake your docker image/deleted the old regularly installed python packages? I didn't at first when I tried it, and I got a list returned that showed all the languages as installed.

sergiolaverde0 commented 4 months ago

I don't think it affects it, but I use my usual dev environment, which does not copy the whole folder to the image, rather it just mounts it like it used to be before we had proper docker images.

This is it I think, sorry for not noticing earlier. Some weeks ago I made a PR that would setup the environment variable for the deploy branch, but forgot to replicate it for the dev environment. That's why you can't find the models listed, because Python does not know it has to search them on that location. Add this to your docker-compose-dev.yml:

environment:
    PYTHONPATH: "/var/www/html/storage/app/model"

Did you remake your docker image/deleted the old regularly installed python packages?

I don't, I built one without the extra languages and have been using that one for all this testing. However, I do delete the folder with the models installed regularly.

simjanos-dev commented 4 months ago

Oh. I completely forgot about that. I add it and test it again.

simjanos-dev commented 4 months ago

The list returned Korean, and it does work when importing text. Thank you!

I will work on the UI, then adding the 7~ languages that I mentioned in the other issue. Then probably going to still focus on adding more languages if I can.

simjanos-dev commented 4 months ago

I've changed the language names to capitalized words. I know I suggested the lowercase ones, but just realized that it works much better. Sorry again, for changing the tokenizer file, did not know you were working on it already.

Can we modify the list function, so it returns the missing/not installed languages instead? It will be only used at one place, and it would save an additional config language list in Laravel. I don't know how difficult it is to change the python part.

If we can, would you like me to do it, or would you like to write it yourself?

Thank you so much for working on it by the way, this feature will be great.

simjanos-dev commented 4 months ago

Can we modify the list function, so it returns the missing/not installed languages instead?

Actually, I'm going to need that config anyway, so it does not matter.

simjanos-dev commented 4 months ago

I changed the python language install parameter name to "language".

simjanos-dev commented 4 months ago

I finished the UI for this feature. It seem to work quite well, but will keep testing it.

Tasks left:

After those I will probably add more languages.

simjanos-dev commented 4 months ago

Thai language needed this as well: pip install tzdata. Can you please modify the tokenizer file so it installs this as well?

sergiolaverde0 commented 4 months ago

I can, however I'm surprised I didn't encounter that in testing. PR coming in some minutes.

simjanos-dev commented 4 months ago

I've got this error while uninstalling languages. It is weird, first I thought that I pressed something accidentally on my keyboard, but I was watching docker desktop terminal log, and I can't input anything there. It worked the second time and could not reproduce. I don't think anything should be done about it if it does not happen anymore, but left a comment so you know about it.

Edit: it did happen again.

2024-04-21 23:46:01 172.19.0.4 - - [21/Apr/2024 21:46:01] "GET /models/list HTTP/1.1" 200 8
2024-04-21 23:46:07 Traceback (most recent call last):
2024-04-21 23:46:07   File "/usr/lib/python3.10/wsgiref/handlers.py", line 137, in run
2024-04-21 23:46:07     self.result = application(self.environ, self.start_response)
2024-04-21 23:46:07   File "/usr/local/lib/python3.10/dist-packages/bottle.py", line 993, in __call__
2024-04-21 23:46:07     return self.wsgi(environ, start_response)
2024-04-21 23:46:07   File "/usr/local/lib/python3.10/dist-packages/bottle.py", line 968, in wsgi
2024-04-21 23:46:07     out = self._cast(self._handle(environ))
2024-04-21 23:46:07   File "/usr/local/lib/python3.10/dist-packages/bottle.py", line 876, in _handle
2024-04-21 23:46:07     return route.call(**args)
2024-04-21 23:46:07   File "/usr/local/lib/python3.10/dist-packages/bottle.py", line 1759, in wrapper
2024-04-21 23:46:07     rv = callback(*a, **ka)
2024-04-21 23:46:07   File "/app/tokenizer.py", line 582, in model_remove
2024-04-21 23:46:07     shutil.rmtree("/var/www/html/storage/app/model")
2024-04-21 23:46:07   File "/usr/lib/python3.10/shutil.py", line 725, in rmtree
2024-04-21 23:46:07     _rmtree_safe_fd(fd, path, onerror)
2024-04-21 23:46:07   File "/usr/lib/python3.10/shutil.py", line 658, in _rmtree_safe_fd
2024-04-21 23:46:07     _rmtree_safe_fd(dirfd, fullname, onerror)
2024-04-21 23:46:07   File "/usr/lib/python3.10/shutil.py", line 658, in _rmtree_safe_fd
2024-04-21 23:46:07     _rmtree_safe_fd(dirfd, fullname, onerror)
2024-04-21 23:46:07   File "/usr/lib/python3.10/shutil.py", line 679, in _rmtree_safe_fd
2024-04-21 23:46:07     os.unlink(entry.name, dir_fd=topfd)
2024-04-21 23:46:07 KeyboardInterrupt
2024-04-21 23:46:07 172.19.0.4 - - [21/Apr/2024 21:46:07] "DELETE /models/remove HTTP/1.1" 500 59
simjanos-dev commented 4 months ago

Thai tokenizer does not recognize sentences, which is a problem, both because example sentences cannot be extracted this way, and because Thai uses spaces to separate sentences. Linguacafe does not support keeping white spaces in text except new lines, and I wanted to use the end of sentence indicator to add a space to Thai texts.

However I saw the import spacy_thai line, and I realized that the current install system can be used for outside libraries other than Spacy as well. I'll look for and experiment with an other Thai tokenizer tomorrow.

sergiolaverde0 commented 4 months ago

I had gotten the error when deleting the model folder, but it was always when sending the request too soon after another request so I assumed it was some kind of lock that wouldn't reappear when slowed down by an UI, and it always worked on the second try so I disregarded it.

Do you think we should make it retry in case of error up to a number of times?

simjanos-dev commented 4 months ago

I fixed Thai. :)

Do you think we should make it retry in case of error up to a number of times?

I'm not sure. I've used this error message if it fails:

An error has occurred while uninstalling the languages. Please wait a few seconds, and try again.

I'll leave that decision to you. It seems to fail quite a lot, but I think if it fails, users will try it once or twice again, and it will work, and they don't use it very often, if ever.

However, could you please make it return 200 code even if the directory does not exist? This way if something goes wrong with the list function (I don't think it will, I can't really make a good argument for this to be honest, just feels better), users can still delete the directory, because this way I won't have to disable the button if the list returns 0 installed elements.

simjanos-dev commented 4 months ago

Thai and Turkish are working. I don't add Turkish DeepL, because I will rework DeepL system before v0.11. And I'll add Jellyfin support later, after adding more languages.

I'll update the user manual, then work on adding more languages. I will use this branch for the languages, so I won't create a conflict when it get's merged in.

The only thing missing from this branch to get merged into dev are:

simjanos-dev commented 4 months ago

Since this is 99% functional, can I merge this into dev, because someone started working on #24?

I'm not sure how to best handle conflicts and branches, so far I tried to avoid them.

sergiolaverde0 commented 4 months ago

However, could you please make it return 200 code even if the directory does not exist?

Would 202 Accepted be fine? It would convey more accurately that the request was processed but no change actually happened.

As for the merge, let me change the return code to whatever we agree on and to code and test the retry to avoid scaring users with unnecessary error messages. Tomorrow morning for you it will be ready for merge.

Also remember to build a dev image so I can test the whole stack.

simjanos-dev commented 4 months ago

Would 202 Accepted be fine? It would convey more accurately that the request was processed but no change actually happened.

Yes, that's okay too. So far I only used 500 and 200 codes, and the default one for invalid input data that Laravel uses, because it was really difficult finding codes that fit the error that actually happened.

As for the merge, let me change the return code to whatever we agree on and to code and test the retry to avoid scaring users with unnecessary error messages. Tomorrow morning for you it will be ready for merge.

Okay. But it's also not urgent, please take as much time as you need, we can work on it in this branch as long as it needs. Merging it was just a suggestion to avoid conflicts.

Also remember to build a dev image so I can test the whole stack.

I will. I'm thinking about writing a test soon-ish that would test importing (then later other functions), but not sure when I'll get there. Linguacafe grew too large to test it manually before each release.

A few thoughts:

Forgot to mention it, but I also added missing KanjiVG image downloading for Japanese. It downloads the git repo to the temp folder, unpacks it, then moves the files to the image storage, then deletes temp files.

sergiolaverde0 commented 4 months ago

Would 202 Accepted be fine? It would convey more accurately that the request was processed but no change actually happened.

Yes, that's okay too.

This part is done.

While trying to replicate the error when trying to delete the folder (with little success) I found a very minimal detail: if someone copies a backup of their model folder back to the mounted volume all the files will be there and the languages will be listed as available. However, the line that makes the package cache be refreshed won't be run since it is only run when installing the packages, so importing the language will fail and text won't be able to be tokenized.

I don't know how big of a concern this should be, since it is very specific, requires the user to fool around with the files, and should be solved by restarting the container. And the only solution I can think of involves refreshing the package cache every time a request to the tokenizer is made which might have a noticeable performance impact.

simjanos-dev commented 4 months ago

While trying to replicate the error when trying to delete the folder (with little success) I found a very minimal detail: if someone copies a backup of their model folder back to the mounted volume all the files will be there and the languages will be listed as available. However, the line that makes the package cache be refreshed won't be run since it is only run when installing the packages, so importing the language will fail and text won't be able to be tokenized.

I don't know how big of a concern this should be, since it is very specific, requires the user to fool around with the files, and should be solved by restarting the container. And the only solution I can think of involves refreshing the package cache every time a request to the tokenizer is made which might have a noticeable performance impact.

I think we should just add a note to the user manual that backups should be done while the server is stopped. Worst case they will get an error message when they try to import a text. Do you think it's enough?

simjanos-dev commented 4 months ago

Added 7 new languages, detailed them in a comment in #3.

I will test the new uninstall merge tomorrow, and probably merge this branch into dev if it works. After that I will add Jellyfin support for the new languages, then work on making DeepL dictionaries creatable and removable and writing the user manual.

Not sure when I will release v0.11, I'll probably take my time with it.

Thank you so much for working on this, this is a huge feature! I really appreciate it!

sergiolaverde0 commented 4 months ago

Not sure when I will release v0.11, I'll probably take my time with it

Take your time and let me know if something goes wrong. However, I advise against merging this and the multi user account for the same release, too many things happening at once will make it harder to give support in case something slips past testing. Even one week only should be enough space to let things settle down.

simjanos-dev commented 4 months ago

However, I advise against merging this and the multi user account for the same release

In that case I'll make this into its own update as soon as it gets ready, and also push back admin dictionary page changes to the next update.

After that I'll slow down with updates probably, I'm starting to feel burned out a bit.

simjanos-dev commented 4 months ago

I've tested the 202 uninstall language code, it seem to work. I've finished everything for the languages, the single thing missing is Jellyfin language codes. I'll add them in a few hours, merge this branch into dev, create a dev docker image, and if it works after a last testing, it can be released on my end. Can also be released later if needed, I do not want to rush it.

(For some reason there were a lot of new users in v0.10)

sergiolaverde0 commented 4 months ago

(For some reason there were a lot of new users in v0.10)

Smooth (~ish) installation and good documentation encourages people to try it, even those who didn't plan on practicing a new language. We are more or less riding on the Duolingo effect.

simjanos-dev commented 4 months ago

I've merged it into dev and created a docker image. I'm only tested on my dev environment so far, but it seems to work well.

When you get to testing it, can you please also test these:

I'll test it once again by using the actual dev image in about 2~ hours.

simjanos-dev commented 4 months ago

Tested it on my live environment, looks good.

There's an additional empty models directory on the deploy branch. Currently we use "linguacafe/storage/app/model", but deploy branch has an unused "linguacafe/storage/models/" directory. This can be removed with v0.12.

The current python image is 1.06 GB. There are 19 pre-installed languages + the multilingual model, and there will be 2 more.

sergiolaverde0 commented 4 months ago

When you get to testing it, can you please also test these:

  • After installing Japanese, /storage/app/images/kanjivg folder should exist with lot of svg files.
  • After uninstalling all languages it should disappear.

Can confirm both things are working, as are all of the tokenizers as far as I can tell without knowing anything of two thirds of them. I really like the way the menu to choose a language tells you there are more available to install with the change of contrast.

However at first I had a little brainfart and thought something was wrong because I forgot to switch out from Spanish at first, so I think of adding the option in the message of successful install to switch to the new language to make it entirely foolproof, what do you think?

simjanos-dev commented 4 months ago

so I think of adding the option in the message of successful install to switch to the new language to make it entirely foolproof, what do you think?

I'll do that tomorrow. Also release it after that, if it's okay with you.

sergiolaverde0 commented 4 months ago

Yes, I think we have tested everything we introduced in this version.

simjanos-dev commented 4 months ago

It's published.

I really like the way the menu to choose a language tells you there are more available to install with the change of contrast.

I used the same thing for the new button after installing a language. :) It does not look that great though in light theme.

Thank you so much for working on it, I really appreciate it! It's a huge feature, and now more languages can be added without causing any issues.

sergiolaverde0 commented 4 months ago

Something I forgot to mention: people should run docker image prune to remove the unused layers, otherwise they are kept and use space.