-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
610 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"unused-i18n": patch | ||
--- | ||
|
||
Add unused locales to scaleway-lib |
94 changes: 94 additions & 0 deletions
94
packages/unused-i18n/src/__tests__/processTranslations.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import * as fs from 'fs' | ||
import { beforeEach, describe, expect, it, vi } from 'vitest' | ||
import { processTranslations } from '../index' | ||
import { analyze } from '../lib/analyze' | ||
import { searchFilesRecursively } from '../lib/search' | ||
import { loadConfig } from '../utils/loadConfig' | ||
import { getMissingTranslations } from '../utils/missingTranslations' | ||
import { shouldExclude } from '../utils/shouldExclude' | ||
|
||
// Mock dependencies | ||
vi.mock('fs', () => ({ | ||
existsSync: vi.fn(), | ||
readFileSync: vi.fn(), | ||
writeFileSync: vi.fn(), | ||
})) | ||
|
||
vi.mock('../utils/loadConfig', () => ({ | ||
loadConfig: vi.fn(), | ||
})) | ||
|
||
vi.mock('../lib/search', () => ({ | ||
searchFilesRecursively: vi.fn(), | ||
})) | ||
|
||
vi.mock('../lib/analyze', () => ({ | ||
analyze: vi.fn(), | ||
})) | ||
|
||
vi.mock('../utils/shouldExclude', () => ({ | ||
shouldExclude: vi.fn(), | ||
})) | ||
|
||
vi.mock('../utils/missingTranslations', () => ({ | ||
getMissingTranslations: vi.fn(), | ||
})) | ||
|
||
describe('processTranslations', () => { | ||
beforeEach(() => { | ||
vi.resetAllMocks() | ||
}) | ||
|
||
it('should process translations correctly', async () => { | ||
const config = { | ||
paths: [ | ||
{ | ||
srcPath: ['srcPath'], | ||
localPath: 'localPath', | ||
}, | ||
], | ||
excludeKey: [], | ||
scopedNames: ['scopedT'], | ||
localesExtensions: 'ts', | ||
localesNames: 'en', | ||
ignorePaths: ['folder/file.ts'], | ||
} | ||
|
||
const files = ['file1.ts', 'folder/file.ts'] | ||
const extractedTranslations = ['key1', 'key2'] | ||
const localeContent = ` | ||
export default { | ||
'key1': 'value1', | ||
'key2': 'value2', | ||
'key3': 'value3', | ||
'key4': 'value4', | ||
} as const | ||
`.trim() | ||
|
||
const expectedWriteContent = ` | ||
export default { | ||
'key1': 'value1', | ||
'key2': 'value2', | ||
} as const | ||
`.trim() | ||
|
||
vi.mocked(loadConfig).mockResolvedValue(config) | ||
vi.mocked(searchFilesRecursively).mockReturnValue(files) | ||
vi.mocked(analyze).mockReturnValue(extractedTranslations) | ||
vi.mocked(shouldExclude).mockReturnValue(false) | ||
vi.mocked(getMissingTranslations).mockReturnValue(['key3', 'key4']) | ||
vi.mocked(fs.existsSync).mockReturnValue(true) | ||
vi.mocked(fs.readFileSync).mockReturnValue(localeContent) | ||
vi.mocked(fs.writeFileSync).mockImplementation(vi.fn()) | ||
|
||
await processTranslations({ action: 'remove' }) | ||
|
||
expect(fs.existsSync).toHaveBeenCalledWith('localPath/en.ts') | ||
expect(fs.readFileSync).toHaveBeenCalledWith('localPath/en.ts', 'utf-8') | ||
expect(fs.writeFileSync).toHaveBeenCalledWith( | ||
'localPath/en.ts', | ||
expectedWriteContent, | ||
'utf-8', | ||
) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import * as fs from 'fs' | ||
import { describe, expect, it, vi } from 'vitest' | ||
import { analyze } from '../analyze' | ||
import { extractGlobalT } from '../global/extractGlobalT' | ||
import { extractNamespaceTranslation } from '../scopedNamespace/extractNamespaceTranslation' | ||
import { extractScopedTs } from '../scopedNamespace/extractScopedTs' | ||
|
||
const mockFilePath = '/path/to/test/file.js' | ||
const mockScopedNames = ['scopedT', 'scopedTOne'] | ||
|
||
const fileContent = ` | ||
import { useI18n } from '@scaleway/use-i18n' | ||
const scopedT = namespaceTranslation('namespace'); | ||
{keyLabel ?? scopedT('labelKey1')} | ||
{keyLabel ? scopedT('labelKey2') : scopedT('labelKey3')} | ||
{scopedT(keyLabel ? 'labelKey4' : 'labelKey5')} | ||
{scopedT(\`labelKey6.\${variable}\`)} | ||
{scopedT(variable0)} | ||
{scopedT(\`\${variable1}.\${variable2}\`)} | ||
{t(\`\${variable3}.\${variable4}\`)} | ||
{keyLabel ?? t('labelKey8')} | ||
{keyLabel ? t('labelKey9') : t('labelKey10')} | ||
{t(\`labelKey11.\${variable5}\`)} | ||
{t(\`labelKey12.\${variable6}\`)} | ||
toast.success(t('account.user.modal.edit.changeEmail')); | ||
{ [FORM_ERROR]: t('form.errors.formErrorNoRetry') }; | ||
{scopedTOne('labelKey13', { | ||
name: scopedT('labelKey14') | ||
})} | ||
` | ||
|
||
const expectedTranslationResults = [ | ||
'account.user.modal.edit.changeEmail', | ||
'form.errors.formErrorNoRetry', | ||
'labelKey10', | ||
'labelKey11.**', | ||
'labelKey12.**', | ||
'labelKey8', | ||
'labelKey9', | ||
'**.**', | ||
'namespace.**', | ||
'namespace.**.**', | ||
'namespace.labelKey1', | ||
'namespace.labelKey13', | ||
'namespace.labelKey14', | ||
'namespace.labelKey2', | ||
'namespace.labelKey3', | ||
'namespace.labelKey4', | ||
'namespace.labelKey5', | ||
'namespace.labelKey6.**', | ||
] | ||
|
||
vi.mock('fs') | ||
|
||
vi.mock('../global/extractGlobalT', () => ({ | ||
extractGlobalT: vi.fn(() => [ | ||
'labelKey8', | ||
'labelKey9', | ||
'labelKey10', | ||
'labelKey11.**', | ||
'labelKey12.**', | ||
'account.user.modal.edit.changeEmail', | ||
'form.errors.formErrorNoRetry', | ||
]), | ||
})) | ||
|
||
vi.mock('../scopedNamespace/extractNamespaceTranslation', () => ({ | ||
extractNamespaceTranslation: vi.fn(() => [ | ||
'namespace.labelKey1', | ||
'namespace.labelKey2', | ||
'namespace.labelKey3', | ||
'namespace.labelKey4', | ||
'namespace.labelKey5', | ||
'namespace.labelKey6.**', | ||
'namespace.**', | ||
'namespace.**.**', | ||
]), | ||
})) | ||
|
||
vi.mock('../scopedNamespace/extractScopedTs', () => ({ | ||
extractScopedTs: vi.fn(() => [ | ||
'**.**', | ||
'namespace.**', | ||
'namespace.**.**', | ||
'namespace.labelKey1', | ||
'namespace.labelKey13', | ||
'namespace.labelKey14', | ||
'namespace.labelKey2', | ||
'namespace.labelKey3', | ||
'namespace.labelKey4', | ||
'namespace.labelKey5', | ||
'namespace.labelKey6.**', | ||
]), | ||
})) | ||
|
||
describe('analyze', () => { | ||
it('should extract all translations correctly from the file', () => { | ||
vi.mocked(fs.readFileSync).mockReturnValue(fileContent) | ||
|
||
const result = analyze({ | ||
filePath: mockFilePath, | ||
scopedNames: mockScopedNames, | ||
}) | ||
|
||
expect(fs.readFileSync).toHaveBeenCalledWith(mockFilePath, 'utf-8') | ||
expect(extractGlobalT).toHaveBeenCalledWith({ fileContent }) | ||
expect(extractNamespaceTranslation).toHaveBeenCalledWith({ fileContent }) | ||
|
||
expect(extractScopedTs).toHaveBeenCalledWith({ | ||
fileContent, | ||
namespaceTranslation: 'namespace.labelKey1', | ||
scopedName: 'scopedT', | ||
}) | ||
|
||
expect(extractScopedTs).toHaveBeenCalledTimes(16) | ||
|
||
expect(extractScopedTs).toHaveBeenNthCalledWith(5, { | ||
fileContent, | ||
namespaceTranslation: 'namespace.labelKey5', | ||
scopedName: 'scopedT', | ||
}) | ||
|
||
expect(result).toEqual(expect.arrayContaining(expectedTranslationResults)) | ||
expect(expectedTranslationResults).toEqual(expect.arrayContaining(result)) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import * as fs from 'fs' | ||
import { describe, expect, it, vi } from 'vitest' | ||
import { removeLocaleKeys } from '../remove' | ||
|
||
vi.mock('fs') | ||
|
||
describe('removeLocaleKeys', () => { | ||
it('should remove specified locale keys from the file', () => { | ||
const localePath = 'path/to/locale/en.js' | ||
const missingTranslations = ['key1', 'key4', 'key2'] | ||
|
||
const fileContent = `export default { | ||
'key1': 'value1', | ||
'key2': 'value2', | ||
'key3': 'value3', | ||
'key4': | ||
'value4', | ||
'key5': 'value5', | ||
} as const` | ||
|
||
const expectedContent = ` | ||
export default { | ||
'key3': 'value3', | ||
'key5': 'value5', | ||
} as const` | ||
|
||
const fsMock = { | ||
readFileSync: vi.fn().mockReturnValue(fileContent), | ||
writeFileSync: vi.fn(), | ||
} | ||
|
||
vi.mocked(fs.readFileSync).mockImplementation(fsMock.readFileSync) | ||
vi.mocked(fs.writeFileSync).mockImplementation(fsMock.writeFileSync) | ||
|
||
removeLocaleKeys({ localePath, missingTranslations }) | ||
|
||
expect(fs.readFileSync).toHaveBeenCalledWith(localePath, 'utf-8') | ||
expect(fs.writeFileSync).toHaveBeenCalledWith( | ||
localePath, | ||
expectedContent.trim(), | ||
'utf-8', | ||
) | ||
}) | ||
it('should remove specified locale keys from the file on multi line', () => { | ||
const localePath = 'path/to/locale/en.js' | ||
const missingTranslations = ['key1', 'key5'] | ||
|
||
const fileContent = `export default { | ||
'key1': 'value1', | ||
'key2': 'value2', | ||
'key3': 'value3', | ||
'key4': | ||
'value4', | ||
'key5': 'value5', | ||
} as const` | ||
|
||
const expectedContent = ` | ||
export default { | ||
'key2': 'value2', | ||
'key3': 'value3', | ||
'key4': | ||
'value4', | ||
} as const` | ||
|
||
const fsMock = { | ||
readFileSync: vi.fn().mockReturnValue(fileContent), | ||
writeFileSync: vi.fn(), | ||
} | ||
|
||
vi.mocked(fs.readFileSync).mockImplementation(fsMock.readFileSync) | ||
vi.mocked(fs.writeFileSync).mockImplementation(fsMock.writeFileSync) | ||
|
||
removeLocaleKeys({ localePath, missingTranslations }) | ||
|
||
expect(fs.readFileSync).toHaveBeenCalledWith(localePath, 'utf-8') | ||
expect(fs.writeFileSync).toHaveBeenCalledWith( | ||
localePath, | ||
expectedContent.trim(), | ||
'utf-8', | ||
) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import * as fs from 'fs' | ||
import * as path from 'path' | ||
import { describe, expect, it, vi } from 'vitest' | ||
import { searchFilesRecursively } from "../search" | ||
|
||
vi.mock('fs') | ||
|
||
describe('searchFilesRecursively', () => { | ||
it('should find files where content matches the regex pattern', () => { | ||
const baseDir = 'testDir' | ||
const regex = /use-i18n/ | ||
|
||
const fsMock = { | ||
readdirSync: vi.fn(dir => { | ||
if (dir === baseDir) return ['file1.js', 'file2.js', 'subdir'] | ||
if (dir === path.join(baseDir, 'subdir')) return ['file3.js'] | ||
|
||
return [] | ||
}), | ||
lstatSync: vi.fn(filePath => ({ | ||
isDirectory: () => filePath === path.join(baseDir, 'subdir'), | ||
})), | ||
readFileSync: vi.fn(filePath => { | ||
if (filePath === path.join(baseDir, 'file1.js')) { | ||
return ` | ||
import { useI18n } from '@scaleway/use-i18n' | ||
` | ||
} | ||
if (filePath === path.join(baseDir, 'file2.js')) return 'no match here' | ||
if (filePath === path.join(baseDir, 'subdir', 'file3.js')) { | ||
return ` | ||
import { useI18n } from '@scaleway/use-i18n' | ||
` | ||
} | ||
|
||
return '' | ||
}), | ||
} | ||
|
||
vi.mocked(fs.readFileSync).mockImplementation(fsMock.readFileSync) | ||
// @ts-expect-error mockImplementation no function | ||
vi.mocked(fs.lstatSync).mockImplementation(fsMock.lstatSync) | ||
// @ts-expect-error mockImplementation no function | ||
vi.mocked(fs.readdirSync).mockImplementation(fsMock.readdirSync) | ||
|
||
const expected = [ | ||
path.join(baseDir, 'file1.js'), | ||
path.join(baseDir, 'subdir', 'file3.js'), | ||
] | ||
|
||
const result = searchFilesRecursively({ | ||
baseDir, | ||
regex, | ||
excludePatterns: [], | ||
}) | ||
|
||
expect(result).toEqual(expect.arrayContaining(expected)) | ||
expect(expected).toEqual(expect.arrayContaining(result)) | ||
}) | ||
}) |
Oops, something went wrong.