GithubHelp home page GithubHelp logo

mainmatter / ember-intl-analyzer Goto Github PK

View Code? Open in Web Editor NEW
48.0 9.0 15.0 2.06 MB

Find unused translations in your Ember.js projects

License: MIT License

JavaScript 93.06% Handlebars 6.31% TypeScript 0.64%
emberjs ember-intl i18n translations

ember-intl-analyzer's Introduction

ember-intl-analyzer

Find unused translations in your Ember.js projects

Note

ember-intl-analyzer was written and is maintained by Mainmatter and contributors. We offer consulting, training, and team augmentation for Ember.js – check out our website to learn more!

Usage

npx ember-intl-analyzer

Configuration

ember-intl-analyzer can be configured by creating a config/ember-intl-analyzer.js file in your app:

export default {
  whitelist: [
    /^countries\./,
    /^currency\./,
    /^validations\.errors\./,
    /^[^.]+\.warnings\.[^.]+$/,
  ],
};

whitelist

If you use dynamic translations keys like this:

this.intl.t(`countries.${code}`)

then ember-intl-analyzer can not easily understand what translation keys are being used here. In that case it will ignore the dynamic translation key and show the corresponding translations as unused.

To prevent that from happening you can configure a whitelist, which accepts an array of regular expressions that will be checked when looking for unused translations.

errorOnUnusedWhitelistEntries

When using a whitelist to ignore dynamic translation keys, it can be easy to forget to clean up the whitelist when an entry is not used anymore. You can opt-in to make this analyzer error when this occurs, by setting the errorOnUnusedWhitelistEntries flag in the configuration file:

export default {
  errorOnUnusedWhitelistEntries: true,
};

analyzeConcatExpression

If your template contains translations like this:

{{t (concat "actions." (if @isEditing "save" "publish"))}}

then ember-intl-analyzer does not detect that actions.save and actions.publish are in fact used translations, so they can be incorrectly flagged as missing or unused. As the concat helper can make it harder to read, it's encouraged to rewrite it to for example:

{{if @isEditing (t "actions.save") (t "actions.publish")}}

However, if your application relies heavily on this concat helper, then rewriting may not be the best option for you. In that case, you can opt-in to analyze concat expressions too by setting the analyzeConcatExpression flag in the configuration file:

export default {
  analyzeConcatExpression: true,
};

externalPaths

If your application uses translations provided by (external) addons, then those translations will show up as missing by default. In order to include such translations, you can define externalPaths in the configuration file as follows:

export default {
  externalPaths: ['my-addon'],
};

This example will try to find translation files in node_modules/my-addon/translations. Patterns supported by globby are also possible here, e.g. this:

externalPaths: ['@*/*']

will look up translations in scoped addons like node_modules/@company/scoped-addon/translations.

translationFiles

By default, this addon will try to find missing and unused translations in any YAML or JSON file within the translations folders of your application (['**/*.json', '**/*.yaml', '**/*.yml']). However, if you would like to only analyze a subset of translation files, you can override translationFiles in the configuration file as follows:

export default {
  translationFiles: ['**/en.yaml'],
};

This example will try to find all en.yaml files in the different translations folders, but any patterns supported by globby are also possible here.

babelParserPlugins extensions

If your application uses doesn't parse correctly because it requires a specific babel plugin you can specifiy them in the config file under the key babelParserPlugins a list on plugins can be found here.

For example if you would like typescript support you can specify the typescript plugin, although please note if the plugin introduces a new file extension you will also need to specifiy that in the extensions property. See the examples below.

Typescript example

export default {
  babelParserPlugins: ['typescript'],
  extensions: ['.ts'],
};

Jsx example

export default {
  babelParserPlugins: ['jsx'],
  extensions: ['.jsx'],
};

Gts example
```js
export default {
  babelParserPlugins: ['typescript'],
  extensions: ['.gts'],
};

--fix

If your application has a lot of unused translations you can run the command with the --fix to remove them. Remember to double check your translations as dynamic translations need to be whitelisted or they will be removed!

Custom t helpers

By default this package will only check templates for ember-intl's t helper, but in some cases you may want to create a custom wrapping helper e.g. {{t-error 'error.key' error}} this helper could manage generic error situation but also accept a custom error key. If your app uses custom t helpers you can register them in you config under the helpers key.

Note: This requires the translation key to be the first parameter of the helper

export default {
  helpers: ['t-error'],
};

Caveats

There are a number of things that we do not support yet. Have a look at the Issues before using this project.

Related

  • ember-intl – Internationalization addon for Ember.js

License

This projects is developed by and © Mainmatter GmbH and contributors. It is released under the MIT License.

ember-intl-analyzer's People

Contributors

bertdeblock avatar bobrimperator avatar dependabot-preview[bot] avatar dependabot-support avatar dependabot[bot] avatar ijlee2 avatar jayjayjpg avatar jmonster avatar marcoow avatar mikek2252 avatar patsy-issa avatar poulet42 avatar renovate-bot avatar renovate[bot] avatar robinborst95 avatar turbo87 avatar vstefanovic97 avatar zeppelin 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ember-intl-analyzer's Issues

Add support for experimental `classProperties` Babel plugin

 $ yarn lint:i18n
yarn run v1.17.3
$ npx ember-intl-analyzer
[1/4] 🔍  Finding JS and HBS files...
[2/4] 🔍  Searching for translations keys in JS and HBS files...
SyntaxError: This experimental syntax requires enabling the parser plugin: 'classProperties' (6:21)
    at Parser.raise (/home/lprestonsegoiii/.npm/_npx/12695/lib/node_modules/ember-intl-analyzer/node_modules/@babel/parser/lib/index.js:6325:17)
    at Parser.expectPlugin (/home/lprestonsegoiii/.npm/_npx/12695/lib/node_modules/ember-intl-analyzer/node_modules/@babel/parser/lib/index.js:7647:18)
    at Parser.parseClassProperty (/home/lprestonsegoiii/.npm/_npx/12695/lib/node_modules/ember-intl-analyzer/node_modules/@babel/parser/lib/index.js:10830:12)
    at Parser.pushClassProperty (/home/lprestonsegoiii/.npm/_npx/12695/lib/node_modules/ember-intl-analyzer/node_modules/@babel/parser/lib/index.js:10795:30)
    at Parser.parseClassMemberWithIsStatic (/home/lprestonsegoiii/.npm/_npx/12695/lib/node_modules/ember-intl-analyzer/node_modules/@babel/parser/lib/index.js:10734:14)
    at Parser.parseClassMember (/home/lprestonsegoiii/.npm/_npx/12695/lib/node_modules/ember-intl-analyzer/node_modules/@babel/parser/lib/index.js:10668:10)
    at withTopicForbiddingContext (/home/lprestonsegoiii/.npm/_npx/12695/lib/node_modules/ember-intl-analyzer/node_modules/@babel/parser/lib/index.js:10623:14)
    at Parser.withTopicForbiddingContext (/home/lprestonsegoiii/.npm/_npx/12695/lib/node_modules/ember-intl-analyzer/node_modules/@babel/parser/lib/index.js:9702:14)
    at Parser.parseClassBody (/home/lprestonsegoiii/.npm/_npx/12695/lib/node_modules/ember-intl-analyzer/node_modules/@babel/parser/lib/index.js:10600:10)
    at Parser.parseClass (/home/lprestonsegoiii/.npm/_npx/12695/lib/node_modules/ember-intl-analyzer/node_modules/@babel/parser/lib/index.js:10574:22)

is there a way to tell this to use my project's babel config?
I'm using typescript w/ octane

syntax error: requires decorators parser plugin

running this analyzer in an ember project which uses ember-decorators will cause the following error:

SyntaxError: This experimental syntax requires enabling one of the following parser plugin(s): 'decorators-legacy, decorators'

Details

npx: installed 202 in 44.992s
[1/3] 🔍 Finding JS and HBS files...
[2/3] 🔍 Searching for translations keys in JS and HBS files...
SyntaxError: This experimental syntax requires enabling one of the following parser plugin(s): 'decorators-legacy, decorators' (6:2)
at Parser.raise (/Users/nightire/.npm/_npx/2693/lib/node_modules/ember-intl-analyzer/node_modules/@babel/parser/lib/index.js:6322:17)
at Parser.expectOnePlugin (/Users/nightire/.npm/_npx/2693/lib/node_modules/ember-intl-analyzer/node_modules/@babel/parser/lib/index.js:7653:18)
at Parser.parseDecorator (/Users/nightire/.npm/_npx/2693/lib/node_modules/ember-intl-analyzer/node_modules/@babel/parser/lib/index.js:9945:10)
at withTopicForbiddingContext (/Users/nightire/.npm/_npx/2693/lib/node_modules/ember-intl-analyzer/node_modules/@babel/parser/lib/index.js:10550:32)
at Parser.withTopicForbiddingContext (/Users/nightire/.npm/_npx/2693/lib/node_modules/ember-intl-analyzer/node_modules/@babel/parser/lib/index.js:9657:14)
at Parser.parseClassBody (/Users/nightire/.npm/_npx/2693/lib/node_modules/ember-intl-analyzer/node_modules/@babel/parser/lib/index.js:10539:10)
at Parser.parseClass (/Users/nightire/.npm/_npx/2693/lib/node_modules/ember-intl-analyzer/node_modules/@babel/parser/lib/index.js:10513:22)
at Parser.parseStatementContent (/Users/nightire/.npm/_npx/2693/lib/node_modules/ember-intl-analyzer/node_modules/@babel/parser/lib/index.js:9805:21)
at Parser.parseStatement (/Users/nightire/.npm/_npx/2693/lib/node_modules/ember-intl-analyzer/node_modules/@babel/parser/lib/index.js:9763:17)
at Parser.parseBlockOrModuleBlockBody (/Users/nightire/.npm/_npx/2693/lib/node_modules/ember-intl-analyzer/node_modules/@babel/parser/lib/index.js:10340:25)

Use as part of linting

I'd like to use this as part of npm run lint command, (which does the usual css, js, hbs)

For it to be useful, ember-intl-analyzer would need to return an error rather than a warning.

Perhaps a flag would help for this?

Cannot delete nested translations when using `--fix`

Thanks for creating a really neat tool. I was using the --fix option and this addon threw the following error:

TypeError: Cannot convert undefined or null to object
    at Function.keys (<anonymous>)
    at deleteNestedTranslation (/Users/kcmurphy/.asdf/installs/nodejs/14.16.1/.npm/lib/node_modules/ember-intl-analyzer/index.js:343:14)
    at deleteNestedTranslation (/Users/kcmurphy/.asdf/installs/nodejs/14.16.1/.npm/lib/node_modules/ember-intl-analyzer/index.js:348:7)
    at deleteNestedTranslation (/Users/kcmurphy/.asdf/installs/nodejs/14.16.1/.npm/lib/node_modules/ember-intl-analyzer/index.js:348:7)
    at /Users/kcmurphy/.asdf/installs/nodejs/14.16.1/.npm/lib/node_modules/ember-intl-analyzer/index.js:317:9
    at Array.forEach (<anonymous>)
    at removeUnusedTranslations (/Users/kcmurphy/.asdf/installs/nodejs/14.16.1/.npm/lib/node_modules/ember-intl-analyzer/index.js:313:26)
    at run (/Users/kcmurphy/.asdf/installs/nodejs/14.16.1/.npm/lib/node_modules/ember-intl-analyzer/index.js:83:5)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)

We have lots of nested translations in different files in the following format:

key1:
  key2:
    key3: 'translation'
  key4: 'another translation'
...

and our folder structure is nested as well:

app > translations > folder1 > folder2 > en-ca.yml
app > translations > folder1 > folder2 > fr-ca.yml

app > translations > folder1 > folder3 > en-ca.yml
app > translations > folder1 > folder3 > fr-ca.yml
...

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Rate-Limited

These updates are currently rate-limited. Click on a checkbox below to force their creation now.

  • Replace dependency eslint-plugin-node with eslint-plugin-n 14.0.0
  • Update dependency eslint to v8.57.0
  • Update dependency release-it to v17
  • Lock file maintenance
  • 🔐 Create all rate-limited PRs at once 🔐

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

github-actions
.github/workflows/ci.yml
  • actions/checkout v4
  • actions/setup-node v4
  • actions/checkout v4
  • actions/setup-node v4
npm
fixtures/in-repo-translations/package.json
package.json
  • @babel/parser ^7.13.15
  • @babel/traverse ^7.13.17
  • @glimmer/syntax ^0.80.0
  • chalk ^4.1.1
  • content-tag ^1.1.2
  • emblem ^0.12.1
  • esm ^3.2.25
  • globby ^11.0.3
  • pkg-dir ^5.0.0
  • yaml ^1.10.2
  • eslint 8.56.0
  • eslint-config-prettier 9.1.0
  • eslint-plugin-node 11.1.0
  • eslint-plugin-prettier 4.2.1
  • jest 28.1.3
  • lerna-changelog 2.2.0
  • prettier 2.8.8
  • release-it 14.14.3
  • release-it-lerna-changelog 4.0.1
  • node ^12.22.0 || ^14.17.0 || >=16.0.0

  • Check this box to trigger a request for Renovate to run again on this repository

Shows unused key when used in ternary

When a ternary is used, the translation in the first block is recognized while the second is not, thus failing with the linter job.

Here is a simplified example where the intlService is injected as a parameter function:

function switchKey(intlService, condition) {
  return intlService.t(condition ? 'detected.key': 'ignored.key');
}

I had to change a bit the code so that the second key is recognized, like that:

return condition
   ? intlService.t('detected.key')
   : intlService.t('ignored.key');

Is it a bug, or does the analyzer don't handle conditional keys ?

Allow extending a list of translation helpers for AST analysis

In a project, I have implemented a t-error helper to standardize error handling:

Before:

{{#if (eq error.status 403)}}
  {{t "errors.forbidden"}}
{{else if (gte error.status 400}}
  {{t "errors.server-failure"}}
{{else}}
  {{t "my-component.error-message"}}
{{/if}}

After:

{{t-error error "my-component.error-message"}}

Unfortunately, this forces me to add all fallback keys to ember-intl-analyzer whitelist.

I would like to configure ember-intl-analyzer to recognize my t-error helper. I imagine something like this:

export default {
  whitelist: [
    /^[^.]+\.warnings\.[^.]+$/,
  ],
  helpers: ['t', 't-error'],
};

Is it something we want to support?

PS Please note this should not be sensitive to argument order.

CC @nickschot

Remove unused translations

Currently the run of the plugin gives me a nice list:

❯ npx ember-intl-analyzer
[1/4] 🔍  Finding JS and HBS files...
[2/4] 🔍  Searching for translations keys in JS and HBS files...
[3/4] ⚙️   Checking for unused translations...
[4/4] ⚙️   Checking for missing translations...

 ⚠️   Found 211 unused translations!

   - Identification (used in cs.json)
   - Login (used in cs.json)
   - Password (used in cs.json)
   - Submit (used in cs.json)
   - admin.companies.address (used in cs.json)
...

But now what? I would have to go and manually remove every one of them. Simple shell script might do, but especially when using structured translations (like the last one in my example) this might get tricky.

Allow configuration for final newline

Hi 👋🏼

When running ember-intl-analyzer --fix with JSON translation files, I realised that the formatter trims final newline in translation files

From what I understand by reading the code, this is due to these few lines
Parsing the JSON trims the newline

It would be great if we could add the newline back into the file :)

updatedTranslations = JSON.stringify(translations, null, 2) + '\n';

This would make the behaviour consistent with YAML translation files, since YAML.stringify adds a final newline

In case there are people relying on the newline trimming, maybe we can add this as a configuration param, what do you think?

// config

export default {
  removeFinalNewline: true | false;
}

// index.js

updatedTranslations = JSON.stringify(translations, null, 2);
updatedTranslations += options.removeFinalNewline? '' : '\n';

Incorrectly finds unused translations that are in separate files

Our translations file structure is the following:

app > translations > folder1 > en-ca.yml
app > translations > folder1 > fr-ca.yml

app > translations > folder2 > en-ca.yml
app > translations > folder2 > fr-ca.yml

app > translations > en-ca.yml
app > translations > fr-ca.yml
...

When running ember-intl-analyzer, it incorrectly finds unused translations that are in the files in folder1 and folder2. In our app, we would call them like this.intl.t('folder1.key.for.translation') and this.intl.t('folder2.key.for.translation') respectively.

Support for CJS config file?

Hi! Would it be possible to also support a config file with a CJS export? All JS files located under /config contain CJS exports and are also linted with the node plugin for EsLint. Linting (with the default Ember EsLint configuration) fails when creating a configuration file for ember-intl-analyzer as suggested in the docs. At the moment I just ignore that file. It's probably a stupid request, but support for CJS export would be slightly nicer and more consistent with the rest.

Thanks!

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.