turquoiseowl / i18n

Smart internationalization for ASP.NET
Other
556 stars 156 forks source link

JS browser cache issue with Void url scheme #226

Closed VladMukhitdinov closed 3 years ago

VladMukhitdinov commented 8 years ago

Hi Love your solution! It's really awesome!

We use it as a solution for multiple websites and we decided not to use url localisation. So now we are facing the following issue - when a user switches language everything refreshes except javascripts because browser caches them. As a solution we manually added the locale parameter to the end of javascript link. For example this link http://example.com/somejsfile.js became http://example.com/somejsfile.js?locale=en-US

I think this could be done in i18n automatically. Probably you have already faced this problem. So the question is - what do you think about it and have you planned it as a feature?

Thank you! Vlad

turquoiseowl commented 8 years ago

I'm pleased the library is working for you.

I don't think your question has been raised before.

i18n should be setting the Content-Language header in the response. Have you looked into that at all? I would have hoped that if that header is being set correctly by i18n then the browser cache would take that into account.

From: Vlad Mukhitdinov [mailto:notifications@github.com] Sent: 15 September 2015 22:44 To: turquoiseowl/i18n Subject: [i18n] JS browser cache issue with Void url scheme (#226)

Hi Love your solution! It's really awesome!

We use it as a solution for multiple websites and we decided not to use url localisation. So now we are facing the following issue - when a user switches language everything refreshes except javascripts because browser caches them. As a solution we manually added the locale parameter to the end of javascript link. For example this link http://example.com/somejsfile.js became http://example.com/somejsfile.js?locale=en-US

I think this could be done in i18n automatically. Probably you have already faced this problem. So the question is - what do you think about it and have you planned it as a feature?

Thank you! Vlad

— Reply to this email directly or view it on GitHub https://github.com/turquoiseowl/i18n/issues/226 . https://github.com/notifications/beacon/ADFw_b7pifS8ALVAO-ldgKUUq-McLAo8ks5oyIiogaJpZM4F9-mM.gif

VladMukhitdinov commented 8 years ago

Hi

Thank you for the really fast response!

i18n should be setting the Content-Language header in the response.

Good point. That was my first thought how it could be fixed, but no it didn't work.

turquoiseowl commented 8 years ago

Hmm, I don't see why it's just JS files that have the issue. Any idea?

From: Vlad Mukhitdinov [mailto:notifications@github.com] Sent: 15 September 2015 23:15 To: turquoiseowl/i18n Cc: Martin Connell Subject: Re: [i18n] JS browser cache issue with Void url scheme (#226)

Hi

Thank you for the really fast response!

i18n should be setting the Content-Language header in the response.

Good point. That was my first thought how it could be fixed, but no it didn't work.

— Reply to this email directly or view it on GitHub https://github.com/turquoiseowl/i18n/issues/226#issuecomment-140561534 . https://github.com/notifications/beacon/ADFw_c3k6ldeHWg-uJaAnmM2XLBFX4MRks5oyI_QgaJpZM4F9-mM.gif

VladMukhitdinov commented 8 years ago

I found that issue with JS because I had translatable nuggets in JS files. It could be the same issue with CSS files or images - I haven't test it.

As I understand it works like this:

  1. When a user first time opens a page, the locale is an automatically detected for example to en-US - Browser requests a file with this link http://example.com/somejsfile.js, this js contains translated nuggets
  2. Then the user changes language from en-US to ru-RU - Browser sends request to the server for the html and not for the js because it recognized that js file haven't been changed (the link to that js is the same http://example.com/somejsfile.js). Here the user can see that the text from js haven't been localized.
  3. Now if a user does the hard refresh Ctrl+F5 - Browser clears its cache and sends a request to get js and other stuff from the server - in this case everything is localized.

As far as I know browser doesn't bother about difference between js(css) files - if a link is the same, then it is the same js(css). So there will be no issue if one uses the url localization, because it is adding language tag to the js links as well as to any other link.

turquoiseowl commented 8 years ago

Yes, that sounds exactly right. I was just wondering about HTML. Are you saying the problem would probably occur with HTML too?

VladMukhitdinov commented 8 years ago

Nope, with html everything is perfectly alright. At least I haven't found any issue with html.

turquoiseowl commented 8 years ago

Are all the web browsers consistent in this regard? Which have you tested?

VladMukhitdinov commented 8 years ago

Yes, behavior of all following browsers is completely the same - last versions of Chrome, Firefox, and IE11

turquoiseowl commented 8 years ago

Hmm, I'm not sure what to suggest. Given that the problem does not manifest itself with HTML but does with JS requests makes me think we need to understand that before implementing special handling for JS requests.

VladMukhitdinov commented 8 years ago

Sure, a proper research will be a good thing before making any changes. As for me, the reason why the behavior is different is just because Browsers are processing js,css and other "static" content differently than HTML.

turquoiseowl commented 8 years ago

Okay, possibly the relevant differences between the 'static' content response and the HTML response are the Expires/Cache-Control header settings in the response. Would you be able to confirm this?

I'm coming round to accepting your suggestion, even though it seems to hack HTTP. What do you think about shoving the langtag in the ETag response header for these 'static' resources?

http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.3

VladMukhitdinov commented 8 years ago

What do you think about shoving the langtag in the ETag response header for these 'static' resources?

I think it's worth a try. Thank you!

VladMukhitdinov commented 8 years ago

Sorry, accidentally closed the issue :)

advntss commented 5 years ago

I had similar issue with bundled app.js file of the Vue.js. All vue.js SPA files were included as below:

            bundles.Add(new ScriptBundle("~/bundles/vue").Include(
                    "~/Vue/dist/static/js/manifest*",
                    "~/Vue/dist/static/js/vendor*",
                    "~/Vue/dist/static/js/app*"
            ));

By default, when using@Scripts.Render("~/bundles/vue") It recognizes bundled resource and renders url with hash included /bundles/vue?v=Xohjq_dQ0u_lRHMFzwAyXE6VbWCHMOZA2xQi002iQJ01

But I had a problem with add custom query parameter [lang] as below @Scripts.Render("~/bundles/vue?lang=" + Request.Cookies["i18n.langtag"]?.Value) Seems like it treated the path like a static resource, and rendered path without hash /bundles/vue?lang=en-En this lead to non-expiring cached scripts. So, after updating the site - cached scripts were not updated on clients until forced refresh by pressing Ctrl+F5

As a solution I got cache working by using Scripts.Url("~/bundles/vue") which returns hashed path to bundled resources. @Scripts.Render("~" + Scripts.Url("~/bundles/vue") + "&lang=" + Request.Cookies["i18n.langtag"]?.Value))

With that, correct path is being rendered /bundles/vue?v=Xohjq_dQ0u_lRHMFzwAyXE6VbWCHMOZA2xQi002iQJ01&lang=en-En with included both version hash and language

alexvazquez commented 3 years ago

I had similar issue with bundled app.js file of the Vue.js. All vue.js SPA files were included as below:

          bundles.Add(new ScriptBundle("~/bundles/vue").Include(
                  "~/Vue/dist/static/js/manifest*",
                  "~/Vue/dist/static/js/vendor*",
                  "~/Vue/dist/static/js/app*"
          ));

By default, when using@Scripts.Render("~/bundles/vue") It recognizes bundled resource and renders url with hash included /bundles/vue?v=Xohjq_dQ0u_lRHMFzwAyXE6VbWCHMOZA2xQi002iQJ01

But I had a problem with add custom query parameter [lang] as below @Scripts.Render("~/bundles/vue?lang=" + Request.Cookies["i18n.langtag"]?.Value) Seems like it treated the path like a static resource, and rendered path without hash /bundles/vue?lang=en-En this lead to non-expiring cached scripts. So, after updating the site - cached scripts were not updated on clients until forced refresh by pressing Ctrl+F5

As a solution I got cache working by using Scripts.Url("~/bundles/vue") which returns hashed path to bundled resources. @Scripts.Render("~" + Scripts.Url("~/bundles/vue") + "&lang=" + Request.Cookies["i18n.langtag"]?.Value))

With that, correct path is being rendered /bundles/vue?v=Xohjq_dQ0u_lRHMFzwAyXE6VbWCHMOZA2xQi002iQJ01&lang=en-En with included both version hash and language

Do you need some configuration to activate the "i18n.langtag" cookie? I just set a breakpoint exactly where the Scripts.Render happens and i dont have any cookie with that refrence something about i18.

Appreciate any help.

turquoiseowl commented 3 years ago

The cookie gets created in your language selection code:

https://github.com/turquoiseowl/i18n#explicit-user-language-selection

turquoiseowl commented 3 years ago

If the JS resources are not served by a URL that contains the langtag in the path (e.g. because you are using UrlLocalizationScheme.Void), then I think you will need to append the langtag describing the current PAL to the query string of that URL, as described above.

Instead of using the i18n.langtag cookie to get the PAL, you should be able to get the PAL of the current request into your view code as follows:

@Context.GetPrincipalAppLanguageForRequest()

See the PAL link above for more on this.

alexvazquez commented 3 years ago

Thanks a lot, I could get the javascript cache problem solved.

turquoiseowl commented 3 years ago

Great!

alexvazquez commented 3 years ago

Great!

@turquoiseowl I think I was wrong on the cache problem solved. I tested the application in Incognito mode and is not working. Something about the cache is not ok.

Found something interesting:

  1. As you said somewhere you have to disable static compression in IIS so javascript files are treated correctly
  2. If you use minification and bundle in ASP.NET [[[ ]]] might have issues (I read that in another post)

So based on the above, I disable-static compression and also disabled minification.

In my view i have the following:

@{
        var lang = Session["currentLanguage"];

    }

    <script src="~/Scripts/js/login.js?locale=@lang"></script>

Saying that when you add the lang tag to the end of the javascript file will work, so every time you change to another language the browser will get a new file. But the problem comes when you want to modify for example the French message.po then because the browser already has cached the file: login.js?locale=fr then you won't see the changes unless you do a hard refresh on the browser.

This would be annoying to a user that already accessed the application and then you make an update to some translations for a specific language.

So back to the origin of the issue, I think that this won't ever work. What I think is that the only way to get this work for every view you pass to your javascript file a serialized object of your translations and then just use it inside. That way you dont have to deal with this cache problem.

If there is any other solution without the need of doing the above please I beg some help!!