Welcome to my GH profile
I'm Maxim Vishnevsky, JavaScript Developer
-
Technologies - JavaScript, TypeScript, Vue.js, React.js, Node.js
-
Languages - Russian, English
The static analyze tool for finding, marking and removing unused and missing i18n translations in your JavaScript project
License: MIT License
I'm trying to use generateFilesPaths
in esm module.
import {generateFilesPaths} from 'i18n-unused'
But it raises ERR_MODULE_NOT_FOUND.
node:internal/process/esm_loader:97
internalBinding('errors').triggerUncaughtException(
^
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '<PROJECT_PATH>/node_modules/i18n-unused/dist/i18n-unused.js' imported from <PROJECT_PATH>/src/myscript.js
Did you mean to import i18n-unused/dist/i18n-unused.cjs?
at new NodeError (node:internal/errors:387:5)
at finalizeResolution (node:internal/modules/esm/resolve:429:11)
at moduleResolve (node:internal/modules/esm/resolve:1006:10)
at defaultResolve (node:internal/modules/esm/resolve:1214:11)
at nextResolve (node:internal/modules/esm/loader:165:28)
at ESMLoader.resolve (node:internal/modules/esm/loader:844:30)
at ESMLoader.getModuleJob (node:internal/modules/esm/loader:431:18)
at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:76:40)
at link (node:internal/modules/esm/module_job:75:36) {
code: 'ERR_MODULE_NOT_FOUND'
}
{
...
"type": "module",
"dependencies": {
"flat": "^5.0.2",
"i18n-unused": "0.13.0"
},
}
Am I doing anything wrong?
The tool finds the translation keys within the body of a function component but not in its return statement.
In the example below, the tool finds myKey but not otherKey. It detects otherKey as unused...
function MyComponent() {
const [t] = useTranslation();
const text = t('myKey');
return (
<div>{t('otherKey')}</div>
);
}
While using the popular i18n library, I discovered that I needed to specify __
in the regex.
/(?:[$ .](__))\(.*?\)/gi
Or more generally
const defaultValues = {
// ...
translationKeyMatcher: : /(?:[$ .](_|t|tc|i18nKey|__))\(.*?\)/gi,
// ...
};
I am leaving this here for others in the future or if people are having issues with other translation libraries.
i18n-unused is a must-have if you are doing internationalization with JS. Imprecive work mxmvshnvsk
There is a difference when using display and remove unused translations. When using remove translations, localNameResolver is not used, thus removing translations from wrong files.
I have keys in files such as en-us.json
and the keys are in flat translation format.
{
"common.edit":{
"text": "Edit",
"note" : ""
},
...
}
common.edit
has been used in a component like text: `${t("common.edit")}`
where t
is imported from the translation file.
When I run i18n-unused display-unused common.edit
is also displayed, although it has been used. I tried to mark unused keys, common.edit
and all the keys in the .json
are all marked as unused.
common.edit.text [UNUSED] undefined
common.edit.note [UNUSED] undefined
When I run i18n-unused remove-unused `, no key is remove.
// config i18n-unused.config.js
module.exports = {
localesPath: 'src/localize/locales',
srcPath: 'src',
};
I am not sure where I have gone wrong. Any help, I will appreciate.
If we use this tool in our nuxt application with Gettext translations, we always get 0 results even if we create new, unused keys:
i18n-unused --locales-extensions po --src-path components --locales-path assets/i18n display-unused
Love the repo nice job.
I'm trying to use this as part of ci and fail when there is an unused key however I'm unable to do this because displayUnusedTranslations
just logs to the console instead of returning useful pieces of data like the number of unusedKeys. I forked your repo and I'm building out that functionality so may have a pull request for you soon.
I think it would be convenient if there was an opportunity to choose whether to process the translationKey
in the commented out lines of code
i18next-react project setup:
// ./i18n-unused.config.cjs
module.exports = {
localesPath: 'src/analysis/_locales',
srcPath: 'src',
};
translation files
./src/analysis/_locales/de.json
./src/analysis/_locales/en.json
(reduced for brevity)
{
"tab": {
"progress": "Progress",
}
}
example file that uses translations
// ./src/analysis/views/TestView.tsx
import { useTranslation } from 'react-i18next';
export const TestView = () => {
const { t } = useTranslation('analysis');
return <div>{t('tab.progress')}</div>;
};
i have installed i18n-unused
as dev dependency and run yarn i18n-unused display-unused
this prints almost all translations as unused. what i noticed is that it works with translations that are in javascript (like useEffect
, or other pure javascript contexts), but it does not seem to work in jsx
at all.
Create vendors code bundle, make compatibility with old node versions
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, Thank you for the nice package!
Do you plan to provide type definition file?
To use "Usage in code" comfortably with ts files.
i18n-unused currently marks plural messages as unused, even when the non-plural version is in use. Same goes for contextual messages.
For example in i18next the keys key_one
, key_other
(formerly key
and key_plural
) were both used by t('key', {count: n})
. i18n-unused would mark all of these except key
as unused leading to plurals being potentially deleted.
It's also possible to include context in message keys.
i18n-unused does have excludeKey. But we don't want to exclude these keys, we want key_one
to be treated as equivalent to key
so that if key
stops being used key_one
is properly deleted by i18n-unused remove-unused
.
I understand plural handling isn't consistent and context is fully custom. So perhaps the best solution is either a regexp of suffixes to remove from keys or a function to map message keys to the key used in code.
tried all commands, but everytime i get this:
'i18n-unused' is not recognized as an internal or external command,
operable program or batch file.
Hi there,
It would be awesome if this tool had a configuration for pre-commit
- www.pre-commit.com
First, I want to say thanks for this helpful tool! Unfortunately, I can't figure out how to parse a YAML
locales file (which is directly supported by i18next). I set localesExtensions
to use yml
extension and then want to provide a custom parser. First I thought that I can use localeFileParser
for that, but from looking at the source code it doesn't do what I first thought it does. Is this even possible somehow?
I have translations that are namespaced, i.e.
const { t } = useTranslation(["shared", "thisFeature"]);
const errorTitle = t("shared:error.defaultTitle");
const pageTitle = t("thisFeature:title");
However i18n-unused
does not account for these namespaces, and is showing me that:*
shared:error.defaultTitle
is missing a translation (when running display-missed
).error.defaultTitle
is unused (when running display-unused
).I found an ugly fix where display-unused ignores all files that were posted in display-missed, but I can't use that with remove-unused (unless I update the config json). Adding an option to natively support this would be nice :)
Hi ๐
thank you for the great package ๐ mark-unused and remove-unused worked well for me, but I have an issue using the sync task (see screenshot). localesPath and srcPath is set in the config file (no other settings). node version is 16.13.1
Do you have any suggestions for me on how to get the sync task to work or why it fails?
Thank you in advance ๐
If you set ignoreComments true, the app can skip entire sections of code and report translations unused which are actually used.
A single line comment using /* and */ will cause the app to skip every line of code up to the next comment.
The following is only true if the line begins with '*/' - the '^' character causes the statement to match the beginning of the line:
const isEndOfMultilineComment = (str: string): boolean => /^(*/)/.test(str);
Even if you remove the '^' so the app catches the end of comments using '*/' it still skips code after single line comments.
This code in translations.ts sets skip true and skips subsequent lines of code:
if (isStartOfMultilineComment(_str) || isEndOfMultilineComment(_str)) {
skip = isStartOfMultilineComment(_str);
}
The same statement causes the app to include the line containing '/*' in the case of multiline comments.
To fix these errors:
Remove the '^' in the isEndOfMultilineComment statement:
const isEndOfMultilineComment = (str: string): boolean => /(*/)/.test(str);
Add the following statement to handle single line comments before the above statement:
if (isStartOfMultilineComment(_str) && isEndOfMultilineComment(_str)) {
skip = false;
return acc;
}
Modify this statement to exclude the line with the end of a multiline comment '*/' :
if (skip || isInlineComment(_str) || isHTMLComment(_str)) {
to be:
if (skip || isInlineComment(_str) || isHTMLComment(_str) || isEndOfMultilineComment(_str)) {
react-i18next supports a <Trans i18nKey="key">...<Trans>
component used for messages with html/components as a part.
It would be nice of i18n-unused could find these by default.
Awesome work man! The missing and unused commands helped a lot.
I was wondering if there's a way to define a main language in the locales folder and compare against the other languages to check for missing keys.
Make tests for code base
When I'm running the following command
i18m-unused display-unused
There a lot of translations keys which aren't unused.
Here a examples of patter that do not work
this.$t(
'app.user.confirmation.delete',
{ user: 'MyUser' },
);
this.$t('app.user.confirmation.delete',
{ user: 'MyUser' });
this.$t('app.user.confirmation.delete',
{ user: 'MyUser' },
);
Here are example that work :
(Unfortunately, I cannot place all my translation on a single line , because, I use eslint which force me to not have a ligne with length greater then 100.)
this.$t('app.user.confirmation.delete', { user: 'MyUser' });
Hello and thank you for this package ๐
I'm using this tool in a Nuxtjs
app and the folder structure is pretty flat meaning not everything is under app
or equivalent.
I would like to run this tool against /components
, /pages
, ... But since I can't do that, I'm forced to use the root path.
The problem is that the tool is also running in my node_modules
so it takes a lot a time and can add some noise to the result.
I was wondering if it was possible to add an ignoredPath
option or that srcPath
could take an array of string as argument?
I'm willing to help if you can give me a bit of context on where to start ๐
$ i18n-unused display-unused --locales-path "config/locale"
(node:95074) UnhandledPromiseRejectionWarning: Error: Locales path is required
at initialize (/Users/pain/.asdf/installs/nodejs/14.17.1/.npm/lib/node_modules/i18n-unused/dist/i18n-unused.umd.js:39:13)
at Command.displayUnusedTranslations (/Users/pain/.asdf/installs/nodejs/14.17.1/.npm/lib/node_modules/i18n-unused/dist/i18n-unused.umd.js:148:20)
at Command.listener [as _actionHandler] (/Users/pain/.asdf/installs/nodejs/14.17.1/.npm/lib/node_modules/i18n-unused/node_modules/commander/lib/command.js:466:17)
at /Users/pain/.asdf/installs/nodejs/14.17.1/.npm/lib/node_modules/i18n-unused/node_modules/commander/lib/command.js:1170:65
at Command._chainOrCall (/Users/pain/.asdf/installs/nodejs/14.17.1/.npm/lib/node_modules/i18n-unused/node_modules/commander/lib/command.js:1088:12)
at Command._parseCommand (/Users/pain/.asdf/installs/nodejs/14.17.1/.npm/lib/node_modules/i18n-unused/node_modules/commander/lib/command.js:1170:27)
at Command._dispatchSubcommand (/Users/pain/.asdf/installs/nodejs/14.17.1/.npm/lib/node_modules/i18n-unused/node_modules/commander/lib/command.js:995:25)
at Command._parseCommand (/Users/pain/.asdf/installs/nodejs/14.17.1/.npm/lib/node_modules/i18n-unused/node_modules/commander/lib/command.js:1136:19)
at Command.parse (/Users/pain/.asdf/installs/nodejs/14.17.1/.npm/lib/node_modules/i18n-unused/node_modules/commander/lib/command.js:841:10)
at Object.<anonymous> (/Users/pain/.asdf/installs/nodejs/14.17.1/.npm/lib/node_modules/i18n-unused/bin/i18n-unused.js:48:9)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:95074) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:95074) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
i have setup the config.js as
module.exports = {
localesPath: 'src/locale',
srcPath: 'src',
};
But, on running i18n-unused display-unused , its showing all translations as unused.
Hi! I might be missing something, but I believe some keys are incorrectly reported as unused when they are in fact used as dynamic keys.
For example, in code I have some calls like this:
const errorTitle = I18n.t(`event.api.error.${errorClass}.title`);
return I18n.t(`type.gender.${id}`);
Running the CLI command display-unused
will list keys like those below as being unused, even though they do get used by the code above, which will fill in the dynamic code with a value such as errorClass
or id
.
event.api.error.blocked.title
event.api.error.photoUploadLimit.title
event.api.error.photoUploadSize.title
type.gender.woman
type.gender.man
type.gender.nonBinary
Is there a mechanism to automatically mark those as used? This library does seem to support dynamic keys when finding missing keys, but it only seems to be one-way.
It's working fine (and giving seemingly correct results) with "display-unused". However, when I run "mark-unused" or "remove-unused", I get an error like so:
Successfully marked: /Users/carl/GitHub/opensupply/client/packages/common/src/intl/locales/ar/app.json
(node:18673) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'admin' of undefined
at /Users/carl/GitHub/opensupply/client/node_modules/i18n-unused/dist/i18n-unused.cjs:469:51
at /Users/carl/GitHub/opensupply/client/node_modules/i18n-unused/dist/i18n-unused.cjs:384:7
at Array.reduce (<anonymous>)
at applyToFlatKey (/Users/carl/GitHub/opensupply/client/node_modules/i18n-unused/dist/i18n-unused.cjs:382:16)
at /Users/carl/GitHub/opensupply/client/node_modules/i18n-unused/dist/i18n-unused.cjs:468:37
at Array.forEach (<anonymous>)
at /Users/carl/GitHub/opensupply/client/node_modules/i18n-unused/dist/i18n-unused.cjs:468:22
at Array.forEach (<anonymous>)
at markUnusedTranslations (/Users/carl/GitHub/opensupply/client/node_modules/i18n-unused/dist/i18n-unused.cjs:465:35)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:18673) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:18673) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
It deals with the first file (app.json
) fine, but then gets no further.
Any ideas?
Need to fix this part of issue.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.