GithubHelp home page GithubHelp logo

mxmvshnvsk / i18n-unused Goto Github PK

View Code? Open in Web Editor NEW
125.0 1.0 21.0 509 KB

The static analyze tool for finding, marking and removing unused and missing i18n translations in your JavaScript project

License: MIT License

JavaScript 5.49% TypeScript 94.51%
i18n i18n-js internationalization react vue angular javascript typescript nodejs svelte

i18n-unused's Introduction

Hi there ๐Ÿ‘‹

Welcome to my GH profile
I'm Maxim Vishnevsky, JavaScript Developer

10+ years of experience in web development

  • Technologies - JavaScript, TypeScript, Vue.js, React.js, Node.js

  • Languages - Russian, English

Where to find me

i18n-unused's People

Contributors

1nspir3d avatar alexbbt avatar andyl-ioki avatar asvae avatar athammer avatar bleuscyther avatar blombard avatar donggov avatar jacobmolby avatar medihack avatar mxmvshnvsk avatar yeisonandreylice avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

i18n-unused's Issues

Import from esm module not working

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'
}
  • node version v16.17.0
  • yarn version 1.22.19
  • simplest package.json
{
...
  "type": "module",
  "dependencies": {
    "flat": "^5.0.2",
    "i18n-unused": "0.13.0"
  },
}

Am I doing anything wrong?

Can't find translation keys in the return block of a React component

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>
   );
}

Nodes i18n The translation matcher could include __

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

Locale name resolver not used for remove

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.

Locales path is required

I have the config file on my project root and also tried to set the path using the terminal, but the same error still shows
image
image

remove-unused command, not working on flat Translations

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.

Find nothing

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

Need to be able to access unusedKeys count in ci

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.

every translation in jsx incorrectly flagged as unused

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.

Mark everything as UNUSED

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

Don't mark plurals/context as unused

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.

Can't start

tried all commands, but everytime i get this:
'i18n-unused' is not recognized as an internal or external command,
operable program or batch file.

[Question] How to parse a YAML locales file?

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?

Namespaces are not handled

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

Error when trying to use sync task

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 ๐Ÿ™‚

Bildschirmfoto 2022-06-24 um 16 18 32

ignoreComments skips sections of code when true

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:

  1. Remove the '^' in the isEndOfMultilineComment statement:
    const isEndOfMultilineComment = (str: string): boolean => /(*/)/.test(str);

  2. Add the following statement to handle single line comments before the above statement:
    if (isStartOfMultilineComment(_str) && isEndOfMultilineComment(_str)) {
    skip = false;
    return acc;
    }

  3. 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)) {

Support react-i18next's Trans

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.

Check for missing languages

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.

translationKey on multiline does not work

Here are the package I'm using

Issue

When I'm running the following command

i18m-unused display-unused

There a lot of translations keys which aren't unused.

Example

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' });

Have an ignoredPath option or multiple srcPath

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 ๐Ÿ™‚

Can't 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.

Showing All translation unused

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.

Dynamic keys are incorrectly marked 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.

Fails with error with "mark" and "remove"

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?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.