Skip to content

Commit cc77ff7

Browse files
committed
feat: add unused locales
1 parent b292bdc commit cc77ff7

27 files changed

+986
-64
lines changed

.github/renovate.json

Lines changed: 19 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,63 @@
11
{
22
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
3-
"assignees": [
4-
"team:console"
5-
],
3+
"assignees": ["team:console"],
64
"assigneesSampleSize": 1,
75
"automerge": false,
86
"dependencyDashboard": true,
9-
"enabledManagers": [
10-
"github-actions",
11-
"npm"
12-
],
13-
"extends": [
14-
"config:recommended",
15-
":combinePatchMinorReleases"
16-
],
17-
"labels": [
18-
"dependencies"
19-
],
7+
"enabledManagers": ["github-actions", "npm"],
8+
"extends": ["config:recommended", ":combinePatchMinorReleases"],
9+
"labels": ["dependencies"],
2010
"prConcurrentLimit": 10,
2111
"prHourlyLimit": 5,
2212
"rangeStrategy": "pin",
2313
"rebaseWhen": "auto",
24-
"reviewers": [
25-
"team:console"
26-
],
14+
"reviewers": ["team:console"],
2715
"reviewersSampleSize": 2,
2816
"semanticCommitScope": "deps",
2917
"semanticCommitType": "chore",
30-
"ignorePaths": [
31-
"packages_deprecated/**/package.json"
32-
],
18+
"ignorePaths": ["packages_deprecated/**/package.json"],
3319
"packageRules": [
3420
{
35-
"matchDepTypes": [
36-
"engines",
37-
"peerDependencies"
38-
],
21+
"matchDepTypes": ["engines", "peerDependencies"],
3922
"rangeStrategy": "widen"
4023
},
4124
{
42-
"matchManagers": [
43-
"github-actions"
44-
],
25+
"matchManagers": ["github-actions"],
4526
"semanticCommitScope": "devDeps",
4627
"automerge": true,
4728
"autoApprove": true
4829
},
4930
{
5031
"semanticCommitScope": "devDeps",
51-
"matchDepTypes": [
52-
"packageManager",
53-
"devDependencies"
54-
],
55-
"matchUpdateTypes": [
56-
"major"
57-
]
32+
"matchDepTypes": ["packageManager", "devDependencies"],
33+
"matchUpdateTypes": ["major"]
5834
},
5935
{
6036
"semanticCommitScope": "devDeps",
61-
"matchDepTypes": [
62-
"packageManager",
63-
"devDependencies"
64-
],
65-
"matchUpdateTypes": [
66-
"minor",
67-
"patch"
68-
]
37+
"matchDepTypes": ["packageManager", "devDependencies"],
38+
"matchUpdateTypes": ["minor", "patch"]
6939
},
7040
{
71-
"labels": [
72-
"UPDATE-MAJOR"
73-
],
41+
"labels": ["UPDATE-MAJOR"],
7442
"minimumReleaseAge": "14 days",
75-
"matchUpdateTypes": [
76-
"major"
77-
]
43+
"matchUpdateTypes": ["major"]
7844
},
7945
{
80-
"labels": [
81-
"UPDATE-MINOR"
82-
],
46+
"labels": ["UPDATE-MINOR"],
8347
"minimumReleaseAge": "7 days",
84-
"matchUpdateTypes": [
85-
"minor"
86-
],
48+
"matchUpdateTypes": ["minor"],
8749
"automerge": true,
8850
"autoApprove": true
8951
},
9052
{
91-
"labels": [
92-
"UPDATE-PATCH"
93-
],
53+
"labels": ["UPDATE-PATCH"],
9454
"minimumReleaseAge": "3 days",
95-
"matchUpdateTypes": [
96-
"patch"
97-
],
55+
"matchUpdateTypes": ["patch"],
9856
"automerge": true,
9957
"autoApprove": true
10058
},
10159
{
102-
"matchDepTypes": [
103-
"engines"
104-
],
60+
"matchDepTypes": ["engines"],
10561
"rangeStrategy": "widen"
10662
}
10763
]

eslint.config.mjs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,11 @@ export default [
108108
'import/no-relative-packages': 'off',
109109
},
110110
},
111+
{
112+
files: ['packages/unused-i18n/**/*.ts'],
113+
rules: {
114+
'no-console': 'off',
115+
'no-cond-assign': 'off',
116+
},
117+
},
111118
]

packages/unused-i18n/.eslintrc.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"rules": {
3+
"no-console": "off"
4+
}
5+
}

packages/unused-i18n/.npmignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
**/__tests__/**
2+
examples/
3+
src
4+
.eslintrc.cjs
5+
!.npmignore

packages/unused-i18n/README.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# Unused i18n
2+
3+
Simplifies managing and cleaning up unused translation keys in localization files
4+
5+
## Features
6+
7+
- Analyzes source files to identify used and unused translation keys.
8+
- Supports multiple scoped translation functions.
9+
- Can display or remove unused translation keys.
10+
- Configurable through a JSON, CJS, or JS config file.
11+
12+
## Installation
13+
14+
You can install `unused-i18n` via npm:
15+
16+
```sh
17+
npm install -g unused-i18n
18+
19+
or
20+
21+
npm install -D unused-i18n
22+
```
23+
24+
## Configuration
25+
26+
Create a unused-i18n.config.json or unused-i18n.config.js file in the root of your project. Here's an example configuration:
27+
28+
```cjs
29+
module.exports = {
30+
paths: [
31+
{
32+
srcPath: ['src/pages/products'],
33+
localPath: 'src/pages/products/locales',
34+
},
35+
],
36+
localesExtensions: 'ts',
37+
localesNames: 'en',
38+
scopedNames: ['scopedT', 'scopedTOne'],
39+
ignorePaths: ['src/pages/products/ignoreThisFolder'],
40+
excludeKey: ['someKey'],
41+
}
42+
```
43+
44+
| Option | Type | Default | Required | Description |
45+
| ------------------- | ---------------- | ------- | -------- | ---------------------------------------------------------------------------- |
46+
| `paths` | Array of Objects | `[]` | Yes | An array of objects defining the source paths and local paths to be checked. |
47+
| `paths.srcPath` | Array of Strings | `[]` | Yes | Source paths to search for translations. |
48+
| `paths.localPath` | Strings | `""` | Yes | Path to the translation files. |
49+
| `localesExtensions` | String | `js` | No | Extension of the locale files. |
50+
| `localesNames` | String | `en` | No | Name of the locale files without the extension. |
51+
| `scopedNames` | Array of Strings | `[]` | No | Names of the scoped translation functions used in your project. |
52+
| `ignorePaths` | Array of Strings | `[]` | No | Paths to be ignored during the search. |
53+
| `excludeKey` | Array of Strings | `[]` | No | Specific translation keys to be excluded from the removal process. |
54+
55+
## Usage
56+
57+
### Using with Config File
58+
59+
To use unused-i18n with your config file, simply run:
60+
61+
```sh
62+
npx unused-i18n display
63+
```
64+
65+
### Using with Command Line Options
66+
67+
You can also specify the source and local paths directly in the command line:
68+
69+
##### Display Unused Translations
70+
71+
```sh
72+
npx unused-i18n display --srcPath="src/folders/bla" --localPath="src/folders/bla/locales"
73+
```
74+
75+
##### Remove Unused Translations
76+
77+
```sh
78+
npx unused-i18n remove --srcPath="src/folders/bla" --localPath="src/folders/bla/locales"
79+
```
80+
81+
## API
82+
83+
`processTranslations(paths, action)`
84+
Processes translations based on the specified paths and action.
85+
86+
- paths: Array of objects containing srcPath and localPath.
87+
- action: Action to perform, either 'display' or 'remove'.
88+
89+
## Development
90+
91+
### Building the Project
92+
93+
To build the project, run:
94+
95+
```sh
96+
npm run build
97+
```
98+
99+
#### Running Tests
100+
101+
To run the tests, use:
102+
103+
```sh
104+
npm run test
105+
```
106+
107+
## License
108+
109+
This project is licensed under the MIT License - see the [LICENSE](https://github.com/Lawndlwd/unused-i18n/blob/HEAD/LICENSE) file for details.
110+
111+
## Contributing
112+
113+
Contributions are welcome! Please open an issue or submit a pull request if you have any improvements or suggestions.
114+
115+
Acknowledgements
116+
117+
- [Vite](https://vitejs.dev/) - Next Generation Frontend Tooling.
118+
- [TypeScript](https://www.typescriptlang.org/) - Typed JavaScript used in this project.
119+
- [Vitest](https://vitest.dev/guide/cli) - Testing framework used in this project.
120+
- [Commander](https://github.com/tj/commander.js#readme) - Node.js command-line interfaces.

packages/unused-i18n/package.json

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
{
2+
"name": "unused-i18n",
3+
"version": "0.2.0",
4+
"description": "React provider to handle website end user consent cookie storage based on segment integrations",
5+
"type": "module",
6+
"main": "dist/cli.cjs",
7+
"types": "dist/index.d.ts",
8+
"bin": {
9+
"unused-i18n": "dist/cli.cjs"
10+
},
11+
"files": [
12+
"dist"
13+
],
14+
"publishConfig": {
15+
"access": "public"
16+
},
17+
"scripts": {
18+
"prebuild": "shx rm -rf dist",
19+
"build": "vite build --config vite.config.ts && pnpm run type:generate",
20+
"type:generate": "tsc --declaration -p tsconfig.build.json",
21+
"typecheck": "tsc --noEmit",
22+
"release": "pnpm build && pnpm changeset publish",
23+
"coverage": "vitest run --coverage",
24+
"lint": "eslint --report-unused-disable-directives --cache --cache-strategy content --ext ts,tsx .",
25+
"test:unit": "vitest --run --config vite.config.ts",
26+
"test:unit:coverage": "pnpm test:unit --coverage"
27+
},
28+
"repository": {
29+
"type": "git",
30+
"url": "https://github.com/scaleway/scaleway-lib",
31+
"directory": "packages/unused-i18n"
32+
},
33+
"dependencies": {
34+
"commander": "12.1.0",
35+
"esbuild": "0.24.2"
36+
},
37+
"keywords": [
38+
"i18n",
39+
"unused-i18n",
40+
"i18n-unused",
41+
"locales",
42+
"next-international",
43+
"internationalization",
44+
"translate",
45+
"next"
46+
],
47+
"engines": {
48+
"node": ">=22.x",
49+
"pnpm": ">=9.x"
50+
}
51+
}

packages/unused-i18n/src/cli.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { Command } from 'commander'
2+
import { processTranslations } from './index'
3+
4+
const program = new Command()
5+
6+
program
7+
.command('display')
8+
.description('Display missing translations')
9+
.option('--srcPath path', 'Source path to search for translations')
10+
.option('--localPath path', 'Local path to the translation files')
11+
.action(async (options: { srcPath?: string; localPath?: string }) => {
12+
const paths =
13+
options.srcPath && options.localPath
14+
? [{ srcPath: [options.srcPath], localPath: options.localPath }]
15+
: undefined
16+
await processTranslations({ paths, action: 'display' })
17+
})
18+
19+
program
20+
.command('remove')
21+
.description('Remove unused translations')
22+
.option('--srcPath path', 'Source path to search for translations')
23+
.option('--localPath path', 'Local path to the translation files')
24+
.action(async (options: { srcPath?: string; localPath?: string }) => {
25+
const paths =
26+
options.srcPath && options.localPath
27+
? [{ srcPath: [options.srcPath], localPath: options.localPath }]
28+
: undefined
29+
await processTranslations({ paths, action: 'remove' })
30+
})
31+
32+
program.parse(process.argv)

0 commit comments

Comments
 (0)