![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/domains/lavocat.quebec/private_html/scripts/ |
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const glob = require('glob');
// Patterns to search for hard-coded language navigation
const patterns = [
// Hard-coded language switcher links
{
pattern: /<Link[^>]*href=["']\/en["'][^>]*>.*?EN.*?<\/Link>/gs,
description: 'Hard-coded EN link to /en'
},
{
pattern: /<Link[^>]*href=["']\/["'][^>]*>.*?FR.*?<\/Link>/gs,
description: 'Hard-coded FR link to /'
},
{
pattern: /<Link[^>]*href=["']\/en\/[^"']*["'][^>]*>.*?<\/Link>/gs,
description: 'Hard-coded English page links'
},
{
pattern: /<Link[^>]*href=["']\/(?!en\/)[^"']*["'][^>]*>.*?<\/Link>/gs,
description: 'Hard-coded French page links (excluding /en/ paths)'
},
// Language switcher patterns
{
pattern: /onClick.*?router\.push.*?\/en/gs,
description: 'Router push to /en in onClick handlers'
},
{
pattern: /onClick.*?router\.push.*?\/fr/gs,
description: 'Router push to /fr in onClick handlers'
},
// State-based patterns (these are good, we want to find pages that DON'T have these)
{
pattern: /const \[language, setLanguage\] = useState/gs,
description: 'Language state management (GOOD)',
isGood: true
},
{
pattern: /handleLanguageToggle.*?setLanguage/gs,
description: 'Language toggle handler (GOOD)',
isGood: true
}
];
// Files to scan
const scanPaths = [
'src/pages/**/*.tsx',
'src/pages/**/*.jsx',
'src/components/**/*.tsx',
'src/components/**/*.jsx'
];
// Files to exclude
const excludePatterns = [
'**/node_modules/**',
'**/.next/**',
'**/deployment/**',
'**/*.d.ts',
'**/test-results/**'
];
function scanFile(filePath) {
try {
const content = fs.readFileSync(filePath, 'utf8');
const issues = [];
const hasGoodPatterns = [];
patterns.forEach(({ pattern, description, isGood }) => {
const matches = content.match(pattern);
if (matches) {
if (isGood) {
hasGoodPatterns.push(description);
} else {
issues.push({
description,
matches: matches.length,
examples: matches.slice(0, 2) // Show first 2 examples
});
}
}
});
return {
filePath,
issues,
hasGoodPatterns,
needsConversion: issues.length > 0 && hasGoodPatterns.length === 0
};
} catch (error) {
return {
filePath,
error: error.message
};
}
}
function main() {
console.log('š Scanning for hard-coded language navigation links...\n');
const allFiles = [];
scanPaths.forEach(pattern => {
const files = glob.sync(pattern, { ignore: excludePatterns });
allFiles.push(...files);
});
console.log(`š Found ${allFiles.length} files to scan\n`);
const results = allFiles.map(scanFile);
// Filter results
const filesWithIssues = results.filter(r => r.issues && r.issues.length > 0);
const filesNeedingConversion = results.filter(r => r.needsConversion);
const filesWithGoodPatterns = results.filter(r => r.hasGoodPatterns && r.hasGoodPatterns.length > 0);
// Display results
console.log('š SCAN RESULTS:\n');
console.log(`ā
Files with good state-based patterns: ${filesWithGoodPatterns.length}`);
filesWithGoodPatterns.forEach(file => {
console.log(` - ${file.filePath}`);
file.hasGoodPatterns.forEach(pattern => {
console.log(` ā ${pattern}`);
});
});
console.log(`\nā ļø Files with hard-coded language issues: ${filesWithIssues.length}`);
filesWithIssues.forEach(file => {
console.log(`\nš ${file.filePath}`);
file.issues.forEach(issue => {
console.log(` ā ${issue.description} (${issue.matches} instances)`);
if (issue.examples) {
issue.examples.forEach((example, i) => {
const truncated = example.length > 100 ? example.substring(0, 100) + '...' : example;
console.log(` Example ${i + 1}: ${truncated.replace(/\s+/g, ' ')}`);
});
}
});
});
console.log(`\nšØ Files needing conversion to state-based switching: ${filesNeedingConversion.length}`);
filesNeedingConversion.forEach(file => {
console.log(` š§ ${file.filePath}`);
});
// Summary
console.log('\nš SUMMARY:');
console.log(` - Total files scanned: ${allFiles.length}`);
console.log(` - Files with good patterns: ${filesWithGoodPatterns.length}`);
console.log(` - Files with issues: ${filesWithIssues.length}`);
console.log(` - Files needing conversion: ${filesNeedingConversion.length}`);
if (filesNeedingConversion.length > 0) {
console.log('\nšÆ RECOMMENDATIONS:');
console.log(' 1. Convert hard-coded <Link> components to state-based buttons');
console.log(' 2. Add language state management (useState)');
console.log(' 3. Add handleLanguageToggle function');
console.log(' 4. Make content dynamic using language state');
console.log('\nš” Example conversion:');
console.log(' ā <Link href="/en">EN</Link>');
console.log(' ā
<button onClick={handleLanguageToggle}>{language === "fr" ? "EN" : "FR"}</button>');
}
// Save detailed report
const report = {
timestamp: new Date().toISOString(),
summary: {
totalFiles: allFiles.length,
filesWithGoodPatterns: filesWithGoodPatterns.length,
filesWithIssues: filesWithIssues.length,
filesNeedingConversion: filesNeedingConversion.length
},
filesNeedingConversion: filesNeedingConversion.map(f => f.filePath),
filesWithIssues: filesWithIssues.map(f => ({
filePath: f.filePath,
issues: f.issues
}))
};
fs.writeFileSync('language-scan-report.json', JSON.stringify(report, null, 2));
console.log('\nš Detailed report saved to: language-scan-report.json');
}
if (require.main === module) {
main();
}
module.exports = { scanFile, patterns };