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 :)
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 👍