Skip to content

Commit

Permalink
fet-1603: Scan unused transaltion keys
Browse files Browse the repository at this point in the history
  • Loading branch information
Stanislav Lysak committed Aug 23, 2024
1 parent bd5e3a8 commit 36087a4
Show file tree
Hide file tree
Showing 5 changed files with 216 additions and 58 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"lint:fix": "next lint --fix",
"export": "next export",
"compare-locales": "node ./scripts/compare-locales.mjs",
"scan-locales": "node ./scripts/scan-locales.mjs",
"analyze": "ANALYZE=true pnpm build",
"analyse": "pnpm analyze",
"test": "vitest run",
Expand Down
94 changes: 37 additions & 57 deletions scripts/compare-locales.mjs
Original file line number Diff line number Diff line change
@@ -1,71 +1,51 @@
import fs from 'fs'
import path from 'path'

const BASE_LOCALE = 'en'
const BASE_DIR = 'public/locales'

function listLocales(dirPath, arrayOfFiles) {
arrayOfFiles = arrayOfFiles || []

const files = fs.readdirSync(dirPath)

files.forEach(function (file) {
const fullPath = path.join(dirPath, file)

if (fs.statSync(fullPath).isDirectory()) {
arrayOfFiles.push(fullPath)
listLocales(fullPath, arrayOfFiles) // Recursively list files in subdirectories
} else {
arrayOfFiles.push(fullPath)
}
})

return arrayOfFiles
}

function detectMissingKeys(jsonObject, template) {
let missingKeys = []

for (const key in template) {
if (!jsonObject.hasOwnProperty(key)) {
missingKeys.push(key)
} else if (typeof template[key] === 'object' && !Array.isArray(template[key])) {
const nestedMissingKeys = detectMissingKeys(jsonObject[key], template[key])
if (nestedMissingKeys.length > 0) {
missingKeys = [
...missingKeys,
...nestedMissingKeys.map((nestedKey) => `${key}.${nestedKey}`),
]
import { BASE_LOCALE, getLocalePaths, LOCALES_DIR } from './locale-utils.mjs'

;(() => {
function detectMissingKeys(jsonObject, template) {
let missingKeys = []

for (const key in template) {
if (!jsonObject.hasOwnProperty(key)) {
missingKeys.push(key)
} else if (typeof template[key] === 'object' && !Array.isArray(template[key])) {
const nestedMissingKeys = detectMissingKeys(jsonObject[key], template[key])
if (nestedMissingKeys.length > 0) {
missingKeys = [
...missingKeys,
...nestedMissingKeys.map((nestedKey) => `${key}.${nestedKey}`),
]
}
}
}

return missingKeys
}

return missingKeys
}
const locales = getLocalePaths()

const locales = fs.readdirSync(BASE_DIR).reduce((result, key) => {
result[key] = listLocales(`${BASE_DIR}/${key}`)
return result
}, {})
console.log('locales', locales)

const baseLocale = locales[BASE_LOCALE]
const baseLocale = locales[BASE_LOCALE]

for (const key in locales) {
if (key !== BASE_LOCALE) {
for (const filePath of baseLocale) {
const diffPath = filePath.replace(`/${BASE_LOCALE}/`, `/${key}/`)
const source = JSON.parse(fs.readFileSync(filePath, 'utf-8'))
const template = JSON.parse(
fs.existsSync(diffPath) ? fs.readFileSync(diffPath, 'utf-8') : '{}',
)
for (const key in locales) {
if (key !== BASE_LOCALE) {
for (const filePath of baseLocale) {
const diffPath = filePath.replace(`/${BASE_LOCALE}/`, `/${key}/`)
const source = JSON.parse(fs.readFileSync(filePath, 'utf-8'))
const template = JSON.parse(
fs.existsSync(diffPath) ? fs.readFileSync(diffPath, 'utf-8') : '{}',
)

const keys = detectMissingKeys(template, source)
const keys = detectMissingKeys(template, source)

if (keys.length) {
console.log('\n')
console.log(key, diffPath.replace(BASE_DIR, ''))
console.log(keys.join('\n'))
if (keys.length) {
console.log('\n')
console.log(key, diffPath.replace(LOCALES_DIR, ''))
console.log(keys.join('\n'))
}
}
}
}
}
})()
69 changes: 69 additions & 0 deletions scripts/locale-utils.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import fs from 'fs'
import path from 'path'

export const BASE_LOCALE = 'en'
export const LOCALES_DIR = 'public/locales'

function getDotNotationKeys(obj, parent = '') {
let keys = []

for (let key in obj) {
if (obj.hasOwnProperty(key)) {
const fullKey = parent ? `${parent}.${key}` : key
if (typeof obj[key] === 'object' && obj[key] !== null) {
keys = keys.concat(getDotNotationKeys(obj[key], fullKey))
} else {
keys.push(fullKey)
}
}
}

return keys
}

function listLocales(dirPath, arrayOfFiles) {
arrayOfFiles = arrayOfFiles || []

const files = fs.readdirSync(dirPath)

files.forEach(function (file) {
const fullPath = path.join(dirPath, file)

if (fs.statSync(fullPath).isDirectory()) {
arrayOfFiles.push(fullPath)
listLocales(fullPath, arrayOfFiles) // Recursively list files in subdirectories
} else {
arrayOfFiles.push(fullPath)
}
})

return arrayOfFiles
}

export function getLocalePaths(locale) {
const locales = fs.readdirSync(LOCALES_DIR).reduce((result, key) => {
result[key] = listLocales(`${LOCALES_DIR}/${key}`)
return result
}, {})

if (locale) return locales[locale]

return locales
}

export function getLocaleData(filePaths) {
let keys = []
const namespaces = []

for (const filePath of filePaths) {
const content = fs.readFileSync(filePath, 'utf-8')
const json = JSON.parse(content)

const ns = filePath.split('/').at(-1).replace('.json', '')

namespaces.push(ns)
keys = [...keys, ...getDotNotationKeys({ [ns]: json })]
}

return { keys, namespaces }
}
108 changes: 108 additions & 0 deletions scripts/scan-locales.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import fs from 'fs'
import path from 'path'

import { BASE_LOCALE, getLocaleData, getLocalePaths } from './locale-utils.mjs'

const baseLocale = getLocalePaths(BASE_LOCALE)

;(() => {
const { keys, namespaces } = getLocaleData(baseLocale)

function createRegex(text, { caseInsensitive = true } = {}) {
const escapedPattern = text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
const flags = caseInsensitive ? 'gi' : 'g'
return new RegExp(`\\b${escapedPattern}`, flags)
}

function filterByExt(text, exts = []) {
const regex = new RegExp(`(${exts.join('|')})$`)
return regex.test(text)
}

const dir = './src'
const search = `t('`
const regex = createRegex(search)

const results = {
results: [],
files: [],
}

function extractKey(str) {
const keyRegex = /t\(\s*['"](.+?)['"]\s*,?/
const keyMatch = str.match(keyRegex)
return keyMatch ? keyMatch[1] : null
}

function extractMatch(filePath) {
let match = true
const matches = []
let content = fs.readFileSync(filePath, 'utf-8')

while ((match = regex.exec(content))) {
// /\b(?:t)\s*\(\s*(['\s\S']*?)\s*\)/g
const line = /\b(?:t)\s*\(['"][^'"]+['"][^)]*\)/g.exec(content)?.at(0)
content = content.replace(match?.[0], '').replace(line, '')
matches.push(extractKey(line))
}

return matches
}

function handleResults(filePath) {
const matches = extractMatch(filePath)

if (!matches.length) return

// console.log(`Found ${matches.length} ${search} in ${filePath}:`)
matches.forEach((m) => console.log(m))
// console.log('\n')
results.results = [...results.results, ...matches]
results.files = [...results.files, filePath]
}

// Function to recursively scan files in a directory
function scanFiles({ dir, fn, ext = [] }) {
const files = fs.readdirSync(dir)

files.forEach((file) => {
const filePath = path.join(dir, file)
const stat = fs.statSync(filePath)

if (stat.isDirectory()) {
scanFiles({ dir: filePath, fn, ext }) // Recursively scan subdirectories
} else if (stat.isFile() && filterByExt(file, ext)) {
fn(filePath)
}
})
}

scanFiles({
dir,
fn: handleResults,
ext: ['.ts', '.tsx'],
})

const unusedKeys = []
const foundKeys = [
...new Set(
results.results.map((key) => key.replace(new RegExp(`^(${namespaces.join('|')}).`), '')),
),
]
const modifiedKeys = [
...new Set(keys.map((key) => key.replace(new RegExp(`^(${namespaces.join('|')}).`), ''))),
]

for (const key of modifiedKeys) {
const foundKey = foundKeys.find((k) => key === k)

if (!foundKey) {
unusedKeys.push(key)
}
}

console.log('PROBABLY UNSED KEYS\n')
for (const key of unusedKeys) {
console.log(key)
}
})()
2 changes: 1 addition & 1 deletion src/transaction-flow/transaction/changePermissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const displayItems = (
},
{
label: 'action',
value: t('transaction.description.changePermissions') as string,
value: t('transaction.description.changePermissions'),
},
{
label: 'info',
Expand Down

0 comments on commit 36087a4

Please sign in to comment.