custom-cards/boilerplate-card

Localize fails to detect language if not set on this device

Closed this issue · 6 comments

Checklist:

  • [ x ] I updated to the latest version available
  • [ x ] I cleared the cache of my browser

Release with the issue:
Latest

Last working release (if known):
N/A

Browser and Operating System:
N/A

Description of problem:

The boilerplate card features an example for implementing translations (localize).
The example uses the localStorage object to get the language setting in HA.
This is not a reliable method, since in this object the language is only defined for in the browser that was used for updating the language setting (otherwise localStorage.getItem('selectedLanguage') returns null).
It would be better to take the language from hass.selectedLanguage instead, so the function is not device-dependent.

It falls back to "en" if selectedLanguage is not set in localStorage, requiring hass in the function means that you need to pass down that object everywhere you might want translations.

@ludeeus agreed that it is not desirable to have the localize function depending on the hass object.
But on the other hand, with the current solution users need to make sure that for each device/browser they have set the HA language, or the variable is not present in localStorage, and it falls back to english as you mentioned.
This fallback is not very user-friendly, as the card is perceived as inconsistent/buggy if the translation is not the same for all their devices.

As a workaround, a custom card could implement a 'check' to see if the language is present in localStorage and if not, set it.
This check could be done in the set hass method.
I don't think this is a good way of working though, as i would say you don't want custom cards to 'mess' with the localStorage.

Ideally i'd like to see that the HA frontend would implement such a check, such that Lovelace cards can rely on localStorage.
Curious about your opinion :)

Did some checks, even if you where to use hass.selectedLanguage, it would result in the same.
This is from my installation
image

something needs to be the fallback, and for now, it looks like the current implementation is more stable.

I did some testing as well.
Here's what i did.

I wrapped the line that detects the language in a function:

function getLanguage(): string {
  return (localStorage.getItem('selectedLanguage') || 'en').replace(/['"]+/g, '').replace('-', '_');
}

Apparently, getLanguage() actually returns 'null' (as a string, not actual null).
Don't know why, but multiple users of my custom card reported the same (my card does a console log of the function output).

Also, the hass object has a selectedLanguage and a language property. Don't ask me about the difference.

So i made the workaround like this:

set hass(hass) {
  if (!getLanguage() || getLanguage() == "null" && hass.selectedLanguage) {
    localStorage.setItem("selectedLanguage", hass.selectedLanguage); 
  }
  else if (!getLanguage() || getLanguage() == "null" && hass.language) {
    localStorage.setItem("selectedLanguage", hass.language);
  }
}

With this workaround in place, users who previously had issues with language not being detected, are now reporting that the card translated fine to the language of their HA config.

I cannot really connect the dots here, but if it works, it works.
Again, I don't like having to do this workaround, I would prefer to be able to rely on the localStorage variable to be set.
I'd say there is definitely room for improvement here.

There is no use in setting something that holds the default value.

I think this should work in most cases:

let lang = localStorage.getItem('selectedLanguage')?.replace(/['"]+/g, '').replace('-', '_');
if (!lang) {
	const _hass = document.querySelector("home-assistant").hass
	lang = hass.selectedLanguage || hass.language || "en"
}

I added your suggestion. Works fine, thanks!
It seems like a good best of both worlds solution.
I'm closing this issue, as it is not really a bug.
Maybe consider to add it to the boilerplate card, as it is an improvement that other developers could benefit from as well?
Thanks for the discussion 👍