Skip to content

Commit d0efab5

Browse files
committed
More translations
1 parent 7a2934f commit d0efab5

14 files changed

Lines changed: 177 additions & 69 deletions

File tree

.github/workflows/test.yml

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ jobs:
1414
steps:
1515
- name: Checkout repository
1616
uses: actions/checkout@v4
17-
with:
18-
fetch-depth: 0 # Shallow clones should be disabled for better relevancy of analysis
1917

2018
- name: Setup Node.js
2119
uses: actions/setup-node@v4
@@ -26,21 +24,8 @@ jobs:
2624
- name: Install dependencies
2725
run: npm ci
2826

29-
- name: Run tests with coverage
30-
run: npm run test:coverage
31-
32-
- name: SonarQube Scan
33-
uses: SonarSource/sonarqube-scan-action@master
34-
env:
35-
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
36-
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
37-
38-
- name: Upload coverage reports
39-
uses: actions/upload-artifact@v4
40-
with:
41-
name: coverage-report
42-
path: coverage/
43-
retention-days: 30
27+
- name: Run tests
28+
run: npm test
4429

4530
notify:
4631
name: Notify on Failure

.husky/pre-commit

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
npm run type-check && npm test

package-lock.json

Lines changed: 19 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "devnullifier",
3-
"version": "1.3.0",
3+
"version": "1.3.1",
44
"description": "DevNullifier: Clean application data, dev caches (node_modules, .cache, Library, Binary, Intermediate, etc) with Electron, Vue 3, and Vuetify 3.",
55
"main": "dist-main/main/main.js",
66
"scripts": {
@@ -24,7 +24,8 @@
2424
"test:coverage": "npm run test:coverage:renderer && npm run test:coverage:main",
2525
"test:coverage:renderer": "vitest run --coverage",
2626
"test:coverage:main": "vitest run -c vitest.main.config.ts --coverage",
27-
"release": "electron-builder --publish always"
27+
"release": "electron-builder --publish always",
28+
"prepare": "husky"
2829
},
2930
"keywords": [
3031
"electron",
@@ -61,6 +62,7 @@
6162
"cross-env": "^7.0.3",
6263
"electron": "^37.2.0",
6364
"electron-builder": "^24.0.0",
65+
"husky": "^9.1.7",
6466
"jsdom": "^26.1.0",
6567
"typescript": "^5.8.3",
6668
"vite": "^5.0.0",

src/main/__tests__/dirSize.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@ describe("getDirectorySize", () => {
99

1010
beforeEach(async () => {
1111
// Create a temporary directory
12-
tempDir = path.join(os.tmpdir(), `test-${Date.now()}`);
12+
tempDir = path.join(os.tmpdir(), `test-dirsize-${Date.now()}-${Math.floor(Math.random() * 1000)}`);
1313
if (existsSync(tempDir)) {
1414
await fs.rm(tempDir, { recursive: true, force: true });
1515
}
16-
await fs.mkdir(tempDir);
16+
await fs.mkdir(tempDir, { recursive: true });
1717
});
1818

19+
1920
afterEach(async () => {
2021
// Clean up - remove temp directory and all contents
2122
try {

src/main/__tests__/fileUtils.test.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,28 @@ vi.mock("electron", () => ({
2626

2727
describe("fileUtils", () => {
2828
let tempDir: string;
29-
const mockUserDataPath = path.join(os.tmpdir(), `test-userdata-${Date.now()}`);
29+
let mockUserDataPath: string;
3030

3131
beforeEach(async () => {
3232
vi.clearAllMocks();
33-
// Create temporary directories
34-
tempDir = path.join(os.tmpdir(), `test-${Date.now()}`);
33+
// Create temporary directories with unique names
34+
const suffix = `${Date.now()}-${Math.floor(Math.random() * 1000)}`;
35+
tempDir = path.join(os.tmpdir(), `test-fileutils-${suffix}`);
36+
mockUserDataPath = path.join(os.tmpdir(), `test-userdata-${suffix}`);
37+
3538
if (existsSync(tempDir)) {
3639
await fs.rm(tempDir, { recursive: true, force: true });
3740
}
41+
if (existsSync(mockUserDataPath)) {
42+
await fs.rm(mockUserDataPath, { recursive: true, force: true });
43+
}
44+
3845
await fs.mkdir(tempDir, { recursive: true });
3946
await fs.mkdir(mockUserDataPath, { recursive: true });
4047
setUserDataPath(mockUserDataPath);
4148
});
4249

50+
4351
afterEach(async () => {
4452
// Clean up - remove temp directories and all contents
4553
try {

src/main/appDataCleaner.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -139,16 +139,22 @@ export async function getDirectorySize(dirPath: string): Promise<number> {
139139
const entries = await fs.readdir(dirPath, { withFileTypes: true });
140140
for (const entry of entries) {
141141
const fullPath = path.join(dirPath, entry.name);
142-
if (entry.isDirectory()) {
143-
size += await getDirectorySize(fullPath);
144-
} else {
145-
const stats = await fs.stat(fullPath);
146-
size += stats.size;
142+
try {
143+
if (entry.isDirectory()) {
144+
size += await getDirectorySize(fullPath);
145+
} else {
146+
const stats = await fs.stat(fullPath);
147+
size += stats.size;
148+
}
149+
} catch (err) {
150+
// Ignore errors for individual files/directories (e.g., permission denied, busy)
151+
console.warn(`Error accessing ${fullPath}:`, err);
147152
}
148153
}
149154
} catch (err) {
150-
// Ignore errors (e.g., permission denied) and return size of what we can access.
151-
console.log("Error getting directory size:", err);
155+
// Ignore errors for readdir (e.g., directory deleted while reading)
156+
console.warn(`Error reading directory ${dirPath}:`, err);
152157
}
153158
return size;
154159
}
160+

src/renderer/components/DeveloperCleaner.vue

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ const initialCategories: DeveloperCategory[] = [
7777
detectionFiles: ['main.py', 'requirements.txt', 'pyproject.toml', '.venv/', '*.py'],
7878
cachePatterns: ['__pycache__/', '.pytest_cache/', '.mypy_cache/', '.tox/', '.hypothesis/', '.coverage', 'build/', 'dist/'],
7979
warning: true,
80-
warningText: 'venv/ might be the main virtual environment – be careful if no lockfile exists'
80+
warningText: ''
8181
},
8282
{
8383
id: 'nodejs',
@@ -86,7 +86,7 @@ const initialCategories: DeveloperCategory[] = [
8686
detectionFiles: ['package.json', 'yarn.lock', 'vite.config.js', 'next.config.js', 'tsconfig.json'],
8787
cachePatterns: ['node_modules/', 'dist/', 'build/', '.next/', '.nuxt/', '.angular/', '.vite/', '.turbo/', '.expo/', '.parcel-cache/', '.eslintcache', '.cache/'],
8888
warning: true,
89-
warningText: 'node_modules/ may exist in subfolders if using monorepos'
89+
warningText: ''
9090
},
9191
{
9292
id: 'unity',
@@ -95,7 +95,7 @@ const initialCategories: DeveloperCategory[] = [
9595
detectionFiles: ['Assets/', 'ProjectSettings/', 'Packages/', '*.unity'],
9696
cachePatterns: ['Library/', 'Temp/', 'Obj/', 'Build/', 'Builds/', '.vs/', 'Logs/', 'MemoryCaptures/', 'UserSettings/'],
9797
warning: true,
98-
warningText: 'Library/ is only needed at the Unity project root — safe elsewhere'
98+
warningText: ''
9999
},
100100
{
101101
id: 'unreal',
@@ -104,7 +104,7 @@ const initialCategories: DeveloperCategory[] = [
104104
detectionFiles: ['*.uproject', 'Source/', 'Content/'],
105105
cachePatterns: ['Binaries/', 'Build/', 'Intermediate/', 'Saved/', 'DerivedDataCache/', 'Plugins/**/Intermediate/', 'Plugins/**/Binaries/'],
106106
warning: true,
107-
warningText: 'Saved/Config/ might contain useful settings — review before deleting'
107+
warningText: ''
108108
},
109109
{
110110
id: 'rust',
@@ -121,7 +121,7 @@ const initialCategories: DeveloperCategory[] = [
121121
detectionFiles: ['build.gradle', 'pom.xml', 'AndroidManifest.xml', 'src/main/java/'],
122122
cachePatterns: ['build/', 'out/', '.gradle/', '.idea/', 'target/', '.settings/'],
123123
warning: true,
124-
warningText: '.idea/ may contain custom settings — remove only cache/temp files inside'
124+
warningText: ''
125125
},
126126
{
127127
id: 'dotnet',
@@ -138,7 +138,7 @@ const initialCategories: DeveloperCategory[] = [
138138
detectionFiles: ['CMakeLists.txt', 'Makefile', '.vscode/launch.json', '*.cpp', '*.h'],
139139
cachePatterns: ['build/', 'CMakeFiles/', 'cmake-build-debug/', 'cmake-build-release/', 'Debug/', 'Release/'],
140140
warning: true,
141-
warningText: 'build/ might be used manually — check first'
141+
warningText: ''
142142
},
143143
{
144144
id: 'xcode',
@@ -147,7 +147,7 @@ const initialCategories: DeveloperCategory[] = [
147147
detectionFiles: ['*.xcodeproj', 'Info.plist', 'Podfile', '*.swift'],
148148
cachePatterns: ['DerivedData/', 'build/', '*.xcuserdata/', '*.xcuserdatad/'],
149149
warning: true,
150-
warningText: 'Global DerivedData/ lives in ~/Library/Developer/Xcode/DerivedData'
150+
warningText: ''
151151
},
152152
{
153153
id: 'php',
@@ -156,7 +156,7 @@ const initialCategories: DeveloperCategory[] = [
156156
detectionFiles: ['artisan', 'composer.json', 'routes/web.php', 'app/'],
157157
cachePatterns: ['vendor/', 'bootstrap/cache/', 'storage/framework/cache/', '.phpunit.result.cache'],
158158
warning: true,
159-
warningText: 'Only delete vendor/ if composer.lock is present'
159+
warningText: ''
160160
},
161161
{
162162
id: 'symfony',
@@ -173,7 +173,7 @@ const initialCategories: DeveloperCategory[] = [
173173
detectionFiles: ['.ipynb', 'notebooks/', 'train.py', 'requirements.txt', 'wandb/'],
174174
cachePatterns: ['checkpoints/', 'runs/', 'logs/', '.ipynb_checkpoints/', '.cache/', 'wandb/', 'mlruns/'],
175175
warning: true,
176-
warningText: "Don't delete checkpoints unless you're sure they're not needed"
176+
warningText: ''
177177
},
178178
{
179179
id: 'docker',
@@ -206,7 +206,7 @@ const initialCategories: DeveloperCategory[] = [
206206
detectionFiles: ['.idea/', '.vscode/', '.history/', '*.sublime-*', '.DS_Store'],
207207
cachePatterns: ['.idea/workspace.xml', '.idea/caches/', '.vscode/ipch/', '.DS_Store', 'Thumbs.db'],
208208
warning: true,
209-
warningText: "Don't remove .idea/modules.xml or .vscode/settings.json if project-specific"
209+
warningText: ''
210210
}
211211
]
212212

src/renderer/components/DeveloperCleaner/CacheGroup.vue

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@
3636
</div>
3737
<div :class="secondaryTextClass">
3838
{{ cacheGroup.matches.length }}
39-
{{ cacheGroup.matches.length === 1 ? 'match' : 'matches' }} •
40-
{{ formatSize(cacheGroup.selectedSize) }} of {{
41-
formatSize(cacheGroup.totalSize) }} selected
39+
{{ cacheGroup.matches.length === 1 ? t('common.match') : t('common.matches') }} •
40+
{{ formatSize(cacheGroup.selectedSize) }} {{ t('common.of') }} {{
41+
formatSize(cacheGroup.totalSize) }} {{ t('common.selected') }}
4242
</div>
4343
</div>
4444

@@ -55,16 +55,16 @@
5555
<div class="d-flex justify-space-between align-center mb-2">
5656
<v-btn size="x-small" variant="text" @click="selectAllCachesInGroup(cacheGroup)"
5757
:disabled="allGroupCachesSelected(cacheGroup)">
58-
Select All
58+
{{ t('common.select_all') }}
5959
</v-btn>
6060
<v-btn size="x-small" variant="text" @click="deselectAllCachesInGroup(cacheGroup)"
6161
:disabled="noGroupCachesSelected(cacheGroup)">
62-
Deselect All
62+
{{ t('common.deselect_all') }}
6363
</v-btn>
6464
<v-chip size="x-small" color="primary">
6565
{{cacheGroup.matches.filter(m => m.selected).length}}/{{
6666
cacheGroup.matches.length }}
67-
selected
67+
{{ t('common.selected') }}
6868
</v-chip>
6969
</div>
7070

@@ -89,26 +89,30 @@
8989
<v-divider v-if="cacheGroups.length > 1" class="mt-2 mb-1" />
9090
<div class="d-flex justify-space-between align-center mt-1">
9191
<v-btn size="x-small" variant="text" @click="selectAllCaches" :disabled="allCachesSelected">
92-
Select All
92+
{{ t('common.select_all') }}
9393
</v-btn>
9494
<v-btn size="x-small" variant="text" @click="deselectAllCaches" :disabled="noCachesSelected">
95-
Deselect All
95+
{{ t('common.deselect_all') }}
9696
</v-btn>
9797
<v-chip size="x-small" color="primary">
98-
{{ selectedCacheCount }} of {{ totalCacheCount }}
99-
selected
98+
{{ selectedCacheCount }} {{ t('common.of') }} {{ totalCacheCount }}
99+
{{ t('common.selected') }}
100100
</v-chip>
101101
</div>
102102
</div>
103103
</template>
104104

105105
<script setup lang="ts">
106106
import { computed } from 'vue'
107+
import { useI18n } from 'vue-i18n'
107108
import { useTheme } from 'vuetify'
108109
import type { CacheGroup } from '@/types'
109110
import { getTypeColor } from '@/utils/categoryColors'
110111
import { formatSize } from '@/utils/formatters'
111112
113+
// i18n
114+
const { t } = useI18n()
115+
112116
// Theme
113117
const theme = useTheme()
114118

src/renderer/components/DeveloperCleaner/CategoriesPanel.vue

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
<v-icon :class="{ 'rotate-90': showCategories }" class="mr-2 transition-transform">
77
mdi-chevron-right
88
</v-icon>
9-
{{ t('common.dev_categories') }} ({{ enabledCount }}/{{ categories.length }} {{ t('common.enabled') }})
9+
{{ t('common.dev_categories') }} ({{ enabledCount }}/{{ categories.length }} {{ t('common.enabled')
10+
}})
1011
<v-spacer />
1112
<v-chip size="small" v-if="!hasEnabledCategories"
1213
:color="hasEnabledCategories ? 'success' : 'warning'">
@@ -39,7 +40,9 @@
3940
<v-checkbox v-model="category.enabled" color="primary" hide-details
4041
density="compact" @change="saveCategoryStates" />
4142
<div class="flex-grow-1 ml-1 d-flex align-center justify-space-between">
42-
<span class="text-caption font-weight-medium">{{ category.name }}</span>
43+
<span class="text-caption font-weight-medium">
44+
{{ t('common.category_names.' + category.id) }}
45+
</span>
4346
<v-btn icon variant="text" size="x-small"
4447
@click.stop="showCategoryInfo(category)">
4548
<v-icon size="small" :color="category.warning ? 'warning' : 'info'">

0 commit comments

Comments
 (0)