cibernox / svelte-intl-precompile

I18n library for Svelte.js that analyzes your keys at build time for max performance and minimal footprint
https://svelte-intl-precompile.com
ISC License
274 stars 13 forks source link

Is it possible to tree-shake unused keys? #52

Closed kapalla closed 1 year ago

kapalla commented 2 years ago

I build 5 different apps from a monorepo and all keys are included in each app. Because these apps are running on embedded systems they need to be small as possible. Any idea?

cibernox commented 2 years ago

It depends. While compilation of translations is static (happens in build time), invocation can be quite dynamic.

For instance, an app could have keys for 'inputs.placeholders.name', 'inputs.placeholders.surname', 'inputs.placeholders.address', and in the code might be invoking them with $t('input.placeholders.' + field.name).

This usage is totally correct and reasonable and would prevent us from knowing at build time what keys are used.

I see two possibilities:

  1. Have some kind of utility that reports the keys that seem unused, and let a human decide wether those are really unused or not. That utility would report the three keys in the example as possibly unused but someone should check. If you happen to not use any dynamic invocation then it should be 100% correct.
  2. Some approach I've seen before (not for translations but the same principle can apply) is to instrument translations (which would be easy as they are now functions) so it records what translations are used. Then you run your test suite and a report of the keys used can be generated. If your tests are sufficiently comprehensive that should be able to tell that keys have been used in practice. Essentially this is doing a code coverage reporting on the functions that your translations were compiled into.

Neither of those approaches is perfect but the first one seems "Good Enough ™" to me.

kapalla commented 2 years ago

Thank you! The first approach is also what I prefer. Invoking dynamic keys is definitely a problem. Because of that I‘m calling $t() always statically like classes in TailwindCSS. But my problem is, that I‘ve no idea how to remove unused keys. I’ve tried to use a custom Rollup plugin with a transform hook to modify the json resource files, but at the moment they are getting called in this hook, I have no information which keys are in my modules. Some modules are called after the JSON files.

A.svelte // scan for keys B.svelte // scan for keys en.json // purge unused keys de.json // purge unused keys Other.svelte // keys inside here are missing

cibernox commented 2 years ago

I was proposing printing a report and let developers remove unused keys instead of doing it automatically. Since this approach can have false negatives I think it's safer that way.

kapalla commented 2 years ago

Yes, it is definitely safer. But we have thousands of keys and 7 languages. Also, right now, there are a lot of dead keys which will never be used again. But the main problem is, that App A needs a different set of keys than App B and so on. But we have only one file per language, not per language and app. Doing it automatically is the solution I was searching for. I have written now a rollup plugin which can do this. It's at the moment a quick and dirty solution, but it works. It runs only in build, not dev, scans all keys in the transform hook and replaces var es = {… in the renderChunk hook with only the keys that were found.

Thank you for your help and this repo 🙂