romanvm / django-tinymce4-lite

TinyMCE 4 editor widget for Django
MIT License
126 stars 47 forks source link

Language "locked in" on first page load #45

Closed dcollinsn closed 5 years ago

dcollinsn commented 5 years ago

Hello,

I'm using version 1.7.3 in a website that uses django's built in translation system to allow users to choose a language. When first loading a webpage using my own account, set to English, the TinyMCE editor loads in English. If I then change my account language to Spanish and reload a page with the editor, the editor remains in English until I restart the server. After restarting, the language again matches mine on first page view - Spanish - but remains so even after changing my preferred language, until the next time the server reboots.

I'm creating the TinyMCE widget by defining a field in my models.py:

from tinymce import HTMLField
description = HTMLField(verbose_name=_('Description'))

My form is a simple ModelForm, which does not to anything to self.fields['description'].

Spanish interface, English TinyMCE: Spanish interface, English TinyMCE

The following code in my form fixed the problem, by forcing the get_language call in TinyMCE.init to run in the context of the current request, instead of being saved from the first request after the server last starter:

class EventForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['description'].widget = TinyMCE()

Is this something that can be fixed in django-tinymce4-lite to avoid needing to make this patch in each form that uses it?

romanvm commented 5 years ago

With model field a widget is instantiated only once on Django app start. This is how Django works. So your solution for your particular scenario seems to be correct.

merwok commented 5 years ago

@OP are you importing the gettext or gettext_lazy function as your _ alias?

romanvm commented 5 years ago

I'm closing this issue because of no follow-up.

merwok commented 5 years ago

I think the question in my previous message was irrelevant, I mistunderstood the purpose of the screenshot: this is not an issue with _('Description') in the OP’s code (we see it translated to Spanish in the screenshot), but with the language config of tinymce itself.

I now understand the bug report and agree with it. get_language_config calls django’s get_language in TinyMCE.__init__, but it should be done during rendering so that there is a current request with its specific language. (I saw the issue on a page served in French for a site that defaults to English.)

Please reopen!

merwok commented 5 years ago

The problem is not that the language is looked up at import time!

I use tinymce in the admin only; the form object is created for each request, so TinyMCE.__init__ is called within a request context, and the language code is correct.

The problem is that my language code is fr and language files available with TinyMCE are fr_FR.js and fr_CH.js. (For the record the differences between these two aren’t really country-specific terms, but different choices, mistakes and missing strings.)

I don’t want to change my language code; fr_FR would be incorrect as the audience is in Québec, and I don’t want fr-CA in URLs either. From django viewpoint, it is correct to define the available languages as fr and en.

A proper fix should probably be in TinyMCE itself. But for a quick fix, I’ve tried a small change in django-tinymce4-lite: change get_language_config to fallback to "code_CODE" if language_file_exists(code) is false.

This logic allows various configs to work:

merwok commented 5 years ago

@romanvm This is an issue for all sites that don’t use lang+country codes. Can you reopen and discuss my proposed fix?

romanvm commented 5 years ago

@merwok

This is an issue for all sites that don’t use lang+country codes.

This is not true. E.g., a site with uk country code works perfectly fine. I agree that this may be an issue when Django language code does not match the name of the corresponding TinyMCE translation file. The case of Django's 4-letter code -> TinyMCE's 2-letter code is easy one and it was addressed. But the reverse case is not that obvious because of so many possible 4-letter language codes. I understand that you may prefer fr_FR as the default, but you are not the only user and French is not the only language with country variations, and I don't see the point of addressing specific per-user cases in a generic package. For your case a workaround is pretty simple: just rename TinyMCE's translation file from fr_FR.js to fr.js.

merwok commented 5 years ago

This is not true. E.g., a site with uk country code works perfectly fine.

Right, I misqualified my statement!

I understand that you may prefer fr_FR as the default, but you are not the only user

Well I don’t (my project using tinymce is for an audience in Québec, Canada) but choosing code_CODE when code.js does not exists seemed reasonable.

For your case a workaround is pretty simple: just rename TinyMCE's translation file from fr_FR.js to fr.js.

Well I don’t control the TinyMCE files which are part of django-tinymce’s static files. If there was no other choice I could copy fr_FR.js to fr.js during deployment.

Thanks for the changes in 0bf1a65, I’ll use that to add custom language settings directly in default profile or mce_attrs.

romanvm commented 5 years ago

but choosing code_CODE when code.js does not exists seemed reasonable.

I disagree. In a case when for some language multiple country-specific variants are available, like for French or German or even English, who will decide which country-specific variant should be considered as the "master" one? Personally, I don't know, and, I'm afraid, in some cases this choice may even be politically colored. So I don't want to make that choice.

romanvm commented 5 years ago

This should be fixed in v. 1.7.5. I'm closing this issue.