Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Behind the scenes key generation for @solid-primitives/i18n #493

Open
BierDav opened this issue Aug 16, 2023 · 4 comments
Open

Behind the scenes key generation for @solid-primitives/i18n #493

BierDav opened this issue Aug 16, 2023 · 4 comments

Comments

@BierDav
Copy link
Contributor

BierDav commented Aug 16, 2023

Describe The Problem To Be Solved

As a developer I don't want to have to come up with an project-wide unique key for each piece of text that needs to be internationalized. The given defaultValue with parameters should be enough and the rest should be handled in the background.

Suggest A Solution

A CLI Tool as this Feature requests (#492) could output a hash-map like .json output. And a vite plugin generates theses hashes in advance so that we have identical lookup times, less work and smaller bundles on the client side.

A killer feature would be to automatically determine the hash length so that for small projects only two to three letters do the trick which would also significantly reduce bundle size of these translation json's

@BierDav
Copy link
Contributor Author

BierDav commented Aug 16, 2023

Do you think it's worth the effort?

@thetarnav
Copy link
Member

I don't think I understand.
Could you provide a code example of how the API/experience would look like?
Also I believe a vite plugin and a cli tool would be outside of the scope of a simple runtime primitive.
Although this could be a good idea for a separate community project. Maybe a part of solid-cli. And then we could look at providing the runtime part here.

@BierDav
Copy link
Contributor Author

BierDav commented Aug 17, 2023

The goal is to make internalization as seamless as possible. So that when i use the t function i only have to pass following:

<span>{t({name: "David"},"Hello {{ name }}!"}</span>

or just

<span>{t("Hello World!"}</span>

now when resolving the translation a hash of the string Hello {{ name }}! is used. Because all default values are english (or any other fixed language), we can safely ignore resolving when the current locale is this specifiy language. In case we need to resolve a translation, because the current locale is german, we look up the hash in the provided dict.

The problem now is how to get the hashes into the dict? We could use a cli command for extracting all solid-cli i18n -l en -l de --default-language en --extract -o ./trans. This command generates for each configured language the file with all the hashes and empty values in .json format:
de.json

{
  "8ci32y": {
    "default": "Hello {{ name }}!"
    "value": ""
  }
}

en.json (is skipped because it's the default language)

the default value in de.json is to make it easier for translators to translate, because otherwise they would have no way to lookup the english translation. For production builds we want to remove all the defaults, because they are unnecessary.

Ok so now, we have a ultimate beast of automation. Because the developer can just make as many t calls as he wants, at the end the translator extracts all of them translates them. When the client decides to go for german it just downloads the de.json (without de the default values) and finds all the translations simply by hashing the default value.

There is just one catch, that adds a little bit of work i just discovered: When we change the default value afterwards, there is no way for the extractor to know what the old translation was. In this case the extractor must also output a list of all redundant keys so that the translator can match them up afterwards manually. And i think that's a worth it trade-off because in most cases when you change the default value (the english translation) you might also want to change the other translations. With that you have to at least do something manual with them so you can't miss a changed default value, which could also be a benefit.

I hope I've made my idea clear enough, but if you have any questions left, don't hesitate to ask.

@BierDav
Copy link
Contributor Author

BierDav commented Aug 19, 2023

There is also a second issue, with nested translations, so eg:

function MyButton({tKey, tDefaultValue, ...}) {
    const [t] = useI18n();
    return <button>t(tKey, tDefaultValue)</button>
}

if the export encounters such nested translations, the only thing we can do is to inform the developer or translator about the line of code where it occurs and in this case we need to go back to manual legacy translations with custom keys, but that's not really a problem because this is just an extension and doesn't have to be used.

Further extending

For these nested translations we can offer a vite plugin that monitors all those custom keys and also automatically puts them into a json file.

.... and this would be the ultimate translation experience, wouldn't it? 😉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants