diff --git a/README.md b/README.md index f9aeebff..d667e3e1 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,20 @@ export default { }; ``` +Discover stand-alone translation keys +------------------------------------------------------------------------------ + +By default, only translation keys which are immediately translated are picked up by the analyzer. If you have translation keys which are not immediately translated, but are used in your application, you can mark them using the `translationKey` tagged template util. + +```diff ++ import { translationKey } from 'ember-intl-analyzer/translation-key'; + +- const thisIsAKey = 'this.is.a.key'; ++ const thisIsAKey = translationKey`this.is.a.key`; +``` + +This will mark the key `this.is.a.key` as used in your application, and it will not be flagged as unused by the analyzer. This can be a useful tool to mark keys which are used in your application, so they don't have to be added to the whitelist. + Caveats ------------------------------------------------------------------------------ diff --git a/__snapshots__/test.js.snap b/__snapshots__/test.js.snap index 14fca07b..5f467e45 100644 --- a/__snapshots__/test.js.snap +++ b/__snapshots__/test.js.snap @@ -269,6 +269,20 @@ Map { } `; +exports[`Test Fixtures standalone-translation-key 1`] = ` +"[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... + + 👏 No unused translations were found! + + 👏 No missing translations were found! +" +`; + +exports[`Test Fixtures standalone-translation-key 2`] = `Map {}`; + exports[`Test Fixtures unused-translations 1`] = ` "[1/4] 🔍 Finding JS and HBS files... [2/4] 🔍 Searching for translations keys in JS and HBS files... diff --git a/fixtures/standalone-translation-key/app/controllers/application.js b/fixtures/standalone-translation-key/app/controllers/application.js new file mode 100644 index 00000000..bc132106 --- /dev/null +++ b/fixtures/standalone-translation-key/app/controllers/application.js @@ -0,0 +1,10 @@ +import Controller from '@ember/controller'; +import { tracked } from '@glimmer/tracking'; +import { bar } from '../utils/consts'; + +export default class ApplicationController extends Controller { + @tracked foo; + foo() { + return this.intl.t(bar); + } +} diff --git a/fixtures/standalone-translation-key/app/templates/application.hbs b/fixtures/standalone-translation-key/app/templates/application.hbs new file mode 100644 index 00000000..850dcc06 --- /dev/null +++ b/fixtures/standalone-translation-key/app/templates/application.hbs @@ -0,0 +1,2 @@ +{{t "hbs-translation"}} +{{t (concat "concat-" "expression.is-skipped")}} diff --git a/fixtures/standalone-translation-key/app/utils/consts.js b/fixtures/standalone-translation-key/app/utils/consts.js new file mode 100644 index 00000000..259dea01 --- /dev/null +++ b/fixtures/standalone-translation-key/app/utils/consts.js @@ -0,0 +1,3 @@ +import { translationKey } from 'ember-intl-analyzer/translation-key'; + +export const bar = translationKey`js-standalone-translation`; diff --git a/fixtures/standalone-translation-key/translations/de.json b/fixtures/standalone-translation-key/translations/de.json new file mode 100644 index 00000000..20129851 --- /dev/null +++ b/fixtures/standalone-translation-key/translations/de.json @@ -0,0 +1,4 @@ +{ + "hbs-translation": "Lenkstage", + "js-standalone-translation": "Affentheater (standalone)" +} diff --git a/fixtures/standalone-translation-key/translations/en.json b/fixtures/standalone-translation-key/translations/en.json new file mode 100644 index 00000000..ce60f42f --- /dev/null +++ b/fixtures/standalone-translation-key/translations/en.json @@ -0,0 +1,4 @@ +{ + "hbs-translation": "HBS!", + "js-standalone-translation": "JS Standalone!" +} diff --git a/index.js b/index.js index 5003f9e4..187e36ba 100755 --- a/index.js +++ b/index.js @@ -334,6 +334,13 @@ async function analyzeJsFile(content, userPlugins) { } } }, + TaggedTemplateExpression({ node }) { + if (node.tag.name !== 'translationKey') return; + if (node.quasi.quasis.length === 0) return; + + // handle translationKey`foo.bar` case + translationKeys.add(node.quasi.quasis[0].value.raw); + }, }); return translationKeys; diff --git a/package.json b/package.json index b2f1165a..f0a146ce 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,9 @@ "author": "Tobias Bieniek ", "files": [ "bin", - "index.js" + "index.js", + "translation-key.js", + "translation-key.d.ts" ], "bin": { "ember-intl-analyzer": "bin/cli.js" @@ -32,6 +34,7 @@ "yaml": "^1.10.2" }, "devDependencies": { + "@babel/plugin-transform-modules-commonjs": "^7.24.1", "eslint": "8.56.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-node": "11.1.0", @@ -44,5 +47,14 @@ }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "babel" :{ + "env": { + "test": { + "plugins": [ + "@babel/plugin-transform-modules-commonjs" + ] + } + } } } diff --git a/test.js b/test.js index 6a3d6aa0..005936d3 100644 --- a/test.js +++ b/test.js @@ -1,5 +1,6 @@ const fs = require('fs'); const { run, generateFileList } = require('./index'); +const { translationKey } = require('./translation-key'); let fixtures = fs.readdirSync(`${__dirname}/fixtures/`); @@ -97,3 +98,9 @@ describe('generateFileList', () => { expect(() => generateFileList([])).toThrow('Unexpected empty file list'); }); }); + +describe('translationKey', () => { + test('util returns the exact same string', () => { + expect(translationKey`some.translation.key`).toBe('some.translation.key'); + }); +}); diff --git a/translation-key.d.ts b/translation-key.d.ts new file mode 100644 index 00000000..7c40bad9 --- /dev/null +++ b/translation-key.d.ts @@ -0,0 +1,5 @@ +/** + * Tag stand-alone translation keys with this tagged template literal to have them discovered by `ember-intl-analyzer`. + * @param strings : The translation key to tag. + */ +export function translationKey(strings: TemplateStringsArray): string; diff --git a/translation-key.js b/translation-key.js new file mode 100755 index 00000000..d68cf092 --- /dev/null +++ b/translation-key.js @@ -0,0 +1,3 @@ +export function translationKey(strings) { + return strings[0]; +} diff --git a/yarn.lock b/yarn.lock index 126afb55..a5fb0b82 100644 --- a/yarn.lock +++ b/yarn.lock @@ -112,6 +112,13 @@ dependencies: "@babel/types" "^7.22.5" +"@babel/helper-module-imports@^7.22.15": + version "7.24.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz#6ac476e6d168c7c23ff3ba3cf4f7841d46ac8128" + integrity sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg== + dependencies: + "@babel/types" "^7.24.0" + "@babel/helper-module-imports@^7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz#1a8f4c9f4027d23f520bd76b364d44434a72660c" @@ -133,11 +140,27 @@ "@babel/traverse" "^7.22.5" "@babel/types" "^7.22.5" +"@babel/helper-module-transforms@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz#d7d12c3c5d30af5b3c0fcab2a6d5217773e2d0f1" + integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-module-imports" "^7.22.15" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/helper-validator-identifier" "^7.22.20" + "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== +"@babel/helper-plugin-utils@^7.24.0": + version "7.24.0" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz#945681931a52f15ce879fd5b86ce2dae6d3d7f2a" + integrity sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w== + "@babel/helper-simple-access@^7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" @@ -157,6 +180,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== +"@babel/helper-string-parser@^7.23.4": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz#f99c36d3593db9540705d0739a1f10b5e20c696e" + integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ== + "@babel/helper-validator-identifier@^7.22.20", "@babel/helper-validator-identifier@^7.22.5": version "7.22.20" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" @@ -303,6 +331,15 @@ "@babel/helper-module-transforms" "^7.22.5" "@babel/helper-plugin-utils" "^7.22.5" +"@babel/plugin-transform-modules-commonjs@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz#e71ba1d0d69e049a22bf90b3867e263823d3f1b9" + integrity sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw== + dependencies: + "@babel/helper-module-transforms" "^7.23.3" + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-simple-access" "^7.22.5" + "@babel/polyfill@^7.11.5": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.12.1.tgz#1f2d6371d1261bbd961f3c5d5909150e12d0bd96" @@ -363,6 +400,15 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" +"@babel/types@^7.24.0": + version "7.24.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.0.tgz#3b951f435a92e7333eba05b7566fd297960ea1bf" + integrity sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w== + dependencies: + "@babel/helper-string-parser" "^7.23.4" + "@babel/helper-validator-identifier" "^7.22.20" + to-fast-properties "^2.0.0" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"