#6195 closed New feature (fixed)
Allow caching of the javascript translation library by the client browser
Reported by: | jdetaeye | Owned by: | Aymeric Augustin |
---|---|---|---|
Component: | Documentation | Version: | dev |
Severity: | Normal | Keywords: | i18 javascript |
Cc: | charette.s@… | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | yes |
Easy pickings: | no | UI/UX: | no |
Description
A i18 javascript is dynamically generated by django. The script is recreated with every (admin) view using this library, which doesn't make much sense: the same translation dictionary is returned over and over again to the user, increasing the response times and wasting cpu and bandwidth.
This patch allows the client browser to cache this dictionary locally.
Caveats:
- If a user switches languages on the fly or uses multiple languages at the same time, the javascript library isn't updated automatically to the new language. (A more advanced patch could use the Etag header to cover this case)
- I put a hard-coded value of one day as the maximum time the user's browser can cache the page. This could be made a setting, with a default of infinite?
I'm putting the ticket in 'design decision required' for the core team to evaluate the usefulness of a patch like this and a choosing the good design for a more solid patch.
Attachments (1)
Change History (17)
by , 17 years ago
Attachment: | i18js_caching.patch added |
---|
comment:1 by , 17 years ago
Patch needs improvement: | set |
---|---|
Triage Stage: | Unreviewed → Design decision needed |
comment:2 by , 17 years ago
There isn't much of a case for admin views for this change, I think.
For any non-admin view this can be done using the django.views.decorators.http.conditional_page
, django.views.decorators.cache.cache_page
and django.views.decorators.vary.vary_on_headers
decorators AFAICT. Maybe wrapping the last two up in e.g. django.views.decorators.i18n.cached
would be an idea?
(Obviously, the same decorators could be used for the admin's i18n_view
as well.)
You could try the group and see what people there think.
follow-up: 5 comment:3 by , 17 years ago
You certainly have to work around the first problem you mention. If the user changes the language, the translations they see must all be updated correctly.
comment:4 by , 17 years ago
Triage Stage: | Design decision needed → Someday/Maybe |
---|
comment:5 by , 15 years ago
Replying to jdetaeye:
Caveats:
- If a user switches languages on the fly or uses multiple languages at the same time, the javascript library isn't updated automatically to the new language. (A more advanced patch could use the Etag header to cover this case)
Replying to mtredinnick:
You certainly have to work around the first problem you mention. If the user changes the language, the translations they see must all be updated correctly.
#5691 proposes adding the language name to the cache key.
comment:6 by , 14 years ago
Severity: | → Normal |
---|---|
Type: | → New feature |
comment:9 by , 12 years ago
Resolution: | → wontfix |
---|---|
Status: | new → closed |
I investigated this issue a few months ago for a project of mine.
I found three non-exclusive ways to decorate javascript_catalog
to provide caching.
For providing translations in more than one language, the easiest is to include the language code in the URL with i18n_patterns
.
1) Server-side caching
key_prefix = 'js18n-%s' % get_version() @cache_page(86400, key_prefix=key_prefix)
You need a get_version()
function that returns a different result whenever the translations change. In production, this isn't difficult, but it depends on your deployment strategy, making it hard for Django to provide a generic solution. In development, you have to use the dummy cache to avoid stale translations.
The full translations catalog will be resent every time, but you'll save the generation cost.
2) Client-side caching with If-Modified-Since:
last_modified_date = timezone.now() @last_modified(lambda req, **kw: last_modified_date)
last_modified_date
changes whenever the server is reloaded (in production, because the code was updated; in development, because the dev server auto-reloaded). It's even better if you can set last_modified_date
to the software release date, but that's a bit more difficult to get right than version numbers.
3) Client-side caching with Etag:
etag_value = 'js18n-%s' % get_version() @etag(lambda req, **kw: etag_value)
In production, this is perfect. Unfortunately, it doesn't work well in development, because it's hard to generate an etag_value that's guaranteed to change when you just edit .po and .mo files.
Neither of these techniques can provide proper cache invalidation without application-supplied information about the software version. Therefore, I think it's best to leave the implementation of caching to application developers. The cache framework provides tools to add caching with one-liners.
comment:10 by , 12 years ago
Cc: | added |
---|
comment:11 by , 12 years ago
Component: | Internationalization → Documentation |
---|---|
Resolution: | wontfix |
Status: | closed → new |
Triage Stage: | Someday/Maybe → Accepted |
At the Utrecht sprint we agreed that it's be a good idea to suggest caching in the docs.
Requalifying as a docs ticket and reopening.
comment:12 by , 12 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:13 by , 12 years ago
Added docs as discussed on the django sprint (Utrecht)
pull request here: https://github.com/django/django/pull/779
As discussed I am not referencing https://pypi.python.org/pypi/django-statici18n but it is a great way to pre-generate the files and serve them as static.
I use this for my own projects.
comment:14 by , 12 years ago
Thanks for your work on this patch!
I'd like to keep this digression on caching relatively short. I'll summarize a bit.
The BDFL lifted the restriction on linking to third-party projects. I'll restore the link to django-statici18n.
comment:15 by , 12 years ago
Resolution: | → fixed |
---|---|
Status: | assigned → closed |
simple patch