mxmvshnvsk/i18n-unused

Mark everything as UNUSED

IlliaHohniak-Hexa opened this issue ยท 26 comments

Hi. I just start using it and got strange behaviour - all keys are marked as UNUSED.

My config:

module.exports = {
    localesPath: 'public/locales/en',
    srcPath: 'src',
    flatTranslations: true,
};

Part of my translations file (it's path: public/locales):

  "Enough rest": "Enough rest"
  "onboardingFlow.obRest.option1": "Not enough rest",
  "onboardingFlow.obRest.option2": "Some sleep",
  "onboardingFlow.obRest.option3": "A good rest",

In the code keys are using in 3 ways:

  • t('onboardingFlow.obRest.option1')
  • <Trans i18nKey="onboardingFlow.obRest.option1" />
  • <Trans>Enough rest</Trans>

Some components get keys as props.

I use command i18n-unused mark-unused

Hi, u should look option translationKeyMatcher in docs. Tool can't parse your last example, no match pattern in current logic.

What about keys in other 2 cases? The tool should recognize them

It's public repo, can I try to run script?

unfortunately, it's private project. Can we do it in some other way?

I'll try later

Hi. Did you check it? Maybe we can arrange some call with screen-sharing?

Hi, I'll check it on weekends, too much work on weekdays. If it blocker for u, pr's always open, welcome.

Hi. Did you find some time for this problem?
(no, it's not a real blocker. Just a useful improvement)

This was happening me. To fix and debug the issue (really not a bug just a configuration change needed) I just went into node_modules for this package and did some snooping into the i18n-unused.cjs file and saw the matchKeys var in the collectUnusedTranslations function was returning an empty array in each case. If that's the case for you, you need to update the translationKeyMatcher option in the config file.

For example I added translationKeyMatcher: /(?:__\('(.*)'\))/ig as I'm looking for translations that look like __('translations.are.awesome'),. Make sure your regex is only taking the translations.are.awesome part.

@athammer Hi. Thanks, it really helps me.

And I have one more question to you.
If I have key "Enough rest": "Enough rest". And in the code it looks like <Trans>Enough rest</Trans> (It the old method and we just don't have time to rewrite keys).
How can I write down it in the RegExp? I use this (<Trans>.*?<\/Trans>) and it works fine in the service https://regex101.com
but it still marks such keys.

UPD
With Trans it works. But I got two more moments:

  1. We have big strings, so it's interesting, how it will work if inside Trans we have line break. I mean not br, but just too long string. Or lib works with file without such editors things?
  2. We have something like const buttonTitle = 'common.button.skip' and I added |(['"\w]+\.)+(\w+['"]). In this case script works more then 1h and didn't finish. What can be the problem?

UPD 2
I think it works. I made an error in the RegExp(

Also, now I have problem with i18n-unused display-missed @mxmvshnvsk, can you look, pls?

UnhandledPromiseRejectionWarning: TypeError: object null is not iterable (cannot read property Symbol(Symbol.iterator))
    at /Users/illia/.nvm/versions/node/v12.18.3/lib/node_modules/i18n-unused/dist/i18n-unused.cjs:286:23
    at Array.map (<anonymous>)
    at /Users/illia/.nvm/versions/node/v12.18.3/lib/node_modules/i18n-unused/dist/i18n-unused.cjs:285:107

Hi, it's real problem with regexp, thx @athammer =), I'm not very good in regexp.

Also, @mxmvshnvsk @athammer did you have cases with concatenated strings? For example, I have key
"onboardingFlow.feedbackAge.female.20.text"
and in the code it looks like
onboardingFlow.feedbackAge.${gender}.20.text

So, the lib marked it as UNUSED. It's logical, but maybe you did something with it? Because I think only about adding something like ".concat." to such keys and use option excludeKey.

And pls, look at updated comment above :)

@IlliaHohniak-Hexa, no, it's dynamic key matching, i18n-unused is static analyze tool. But u can use separates without dynamic:

// for example
const femaleTranslation = t('onboardingFlow.feedbackAge.female.20.text');
const maleTranslation = t('onboardingFlow.feedbackAge.male.20.text');

@mxmvshnvsk Why is it RegExp problem? The error is in the lib files

It was response to problem in topic, default regexp ignored keys not in brackets and cases without space before t()

@IlliaHohniak-Hexa Share me you regexp for reproduce in missed case

@mxmvshnvsk translationKeyMatcher: /(t(.?))|(i18nKey=".?")|(".?")|('.?')|(.*?</Trans>)/gi

@IlliaHohniak-Hexa problem in regexp, after match file content we have next collection with your regexp:

// my test code
t('onboardingFlow.obRest.option1')
<Trans i18nKey="onboardingFlow.obRest.option2" />
<Trans>Enough rest</Trans>

// output after parsing translations patterns
[ 't(', 't.', 'ti', 'Tr', 't.', 'ti', '<Trans>Enough rest</Trans>' ]

I'll add guard for this case, but it can affect to performance.

Second problem is replacer, by default tool provide regexp for searching value in rounded brackets.

Now available v0.11.0, u can set option missedTranslationParser, it can be regexp or function, that parse value from token after matching with translationKeyMatcher. Now in tool available getting value from rounded brackets. In future I'll made more flexible way to parse values.

If issue isn't actual, please, close an issue.

@mxmvshnvsk I have error: TypeError: object null is not iterable (cannot read property Symbol(Symbol.iterator))

Like you said I use missedTranslationParser: /(t(.?))|(i18nKey=".?")|(".?")|('.?')|(.*?</Trans>)/gi
And updated lib

Hi. Remove g flag from RegExp.

The same error

Are u sure in this regexp? Did u test it in runtime console?

This is the same regexp as I used for translationKeyMatcher.

RegExp from missedTranslationParser uses in follow case: const [, translation] = v.match(missedTranslationParser) || [];, it means, that after match we'll get an array with our value in second item. Be default in this option I added regexp /\(([^)]+)\)/, it get's value from rounded brackets. You should add regexp for your cases, if u find solution for all cases, u can create PR to repo. Also missedTranslationParser may be a function, that parse string and eject value.

But I still don't understand, why I got such error. And what can I do to fix it?

I thought you use same logic for the translationKeyMatcher, right? So regexp should find all cases it code as translationKeyMatcher do.