-
Notifications
You must be signed in to change notification settings - Fork 142
Commit
…/start
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
require('colors'); | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const { recursiveReadDir } = require('../utils/fsUtils'); | ||
|
||
const LANG_HELPER_REGEXP = /{{\s*lang\s*(?:'|")((?:\w*(?:-\w*)*(\.\w*(?:-\w*)*)*)+)/gmi; | ||
Check warning on line 6 in lib/lang/validator.js GitHub Actions / build (16.x, ubuntu-latest)
|
||
|
||
class LangpathsValidator { | ||
/** | ||
* | ||
* @param {String} themePath | ||
*/ | ||
constructor(themePath) { | ||
this.themePath = themePath; | ||
} | ||
|
||
async run(defaultLang = null) { | ||
const templatesPath = path.join(this.themePath, 'templates'); | ||
const paths = await this.getLangHelpersPaths(templatesPath); | ||
const dedupePaths = [...new Set(paths)]; | ||
const langFiles = await this.getLangFilesContent(defaultLang); | ||
const errors = this.validate(dedupePaths, langFiles); | ||
this.printErrors(errors); | ||
return errors; | ||
} | ||
|
||
printErrors(errors) { | ||
if (errors.length > 0) { | ||
console.log('Warning: Your theme has some missing translations used in the theme:'.yellow); | ||
Check warning on line 29 in lib/lang/validator.js GitHub Actions / build (16.x, ubuntu-latest)
Check warning on line 29 in lib/lang/validator.js GitHub Actions / build (18.x, ubuntu-latest)
|
||
console.log(errors.join('\n').yellow); | ||
} | ||
} | ||
|
||
searchLangPaths(fileContent, path) { | ||
Check failure on line 34 in lib/lang/validator.js GitHub Actions / build (16.x, ubuntu-latest)
|
||
const keys = path.split('.'); | ||
let value = fileContent; | ||
|
||
for (const key of keys) { | ||
if (value && value.hasOwnProperty(key)) { | ||
Check failure on line 39 in lib/lang/validator.js GitHub Actions / build (16.x, ubuntu-latest)
|
||
value = value[key]; | ||
Check warning on line 40 in lib/lang/validator.js GitHub Actions / build (16.x, ubuntu-latest)
|
||
} else { | ||
return false; | ||
Check warning on line 42 in lib/lang/validator.js GitHub Actions / build (16.x, ubuntu-latest)
|
||
} | ||
} | ||
|
||
Check warning on line 45 in lib/lang/validator.js GitHub Actions / build (16.x, ubuntu-latest)
|
||
return value; | ||
} | ||
|
||
validate(paths, langFiles) { | ||
const errors = [ | ||
...this.checkLangFiles(langFiles), | ||
...this.checkForMissingTranslations(paths, langFiles), | ||
]; | ||
return errors; | ||
} | ||
|
||
validate(paths, langFiles) { | ||
Check failure on line 57 in lib/lang/validator.js GitHub Actions / build (16.x, ubuntu-latest)
|
||
const errors = []; | ||
for (const path of paths) { | ||
Check failure on line 59 in lib/lang/validator.js GitHub Actions / build (16.x, ubuntu-latest)
|
||
for (const langFile in langFiles) { | ||
Check failure on line 60 in lib/lang/validator.js GitHub Actions / build (16.x, ubuntu-latest)
Check failure on line 60 in lib/lang/validator.js GitHub Actions / build (16.x, ubuntu-latest)
Check failure on line 60 in lib/lang/validator.js GitHub Actions / build (18.x, ubuntu-latest)
|
||
const translation = this.searchLangPaths(langFiles[langFile], path); | ||
if (!translation) { | ||
errors.push(`Missing translation for ${path} in ${langFile}`); | ||
} | ||
} | ||
} | ||
return errors; | ||
} | ||
|
||
checkLangFiles(files) { | ||
if (files.length === 0) { | ||
return ['No lang files found in your theme']; | ||
} | ||
return []; | ||
} | ||
|
||
async getLangHelpersPaths(templatesPath) { | ||
const files = await recursiveReadDir(templatesPath); | ||
const paths = []; | ||
for await (const file of files) { | ||
const content = await fs.promises.readFile(file, { encoding: 'utf-8' }); | ||
const result = content.matchAll(LANG_HELPER_REGEXP); | ||
const arr = [...result]; | ||
if (arr.length > 0) { | ||
const path = arr[0][1]; | ||
Check failure on line 85 in lib/lang/validator.js GitHub Actions / build (16.x, ubuntu-latest)
|
||
paths.push(path); | ||
} | ||
} | ||
return paths; | ||
} | ||
|
||
async getLangFilesContent(defaultLang = null) { | ||
const filesContent = {}; | ||
const langPath = path.join(this.themePath, 'lang'); | ||
let files = await recursiveReadDir(langPath); | ||
|
||
if (defaultLang) { | ||
files = files.filter((file) => file.includes(defaultLang)); | ||
} | ||
|
||
for await (const file of files) { | ||
const content = await fs.promises.readFile(file, { encoding: 'utf-8' }); | ||
filesContent[file] = JSON.parse(content); | ||
} | ||
return filesContent; | ||
} | ||
} | ||
|
||
module.exports = LangpathsValidator; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
const path = require('path'); | ||
|
||
const LangFilesValidator = require('./validator'); | ||
|
||
describe('lang/validator.js tests', () => { | ||
let consoleLogStub; | ||
Check failure on line 6 in lib/lang/validator.spec.js GitHub Actions / build (16.x, ubuntu-latest)
|
||
|
||
beforeAll(() => { | ||
consoleLogStub = jest.spyOn(console, 'log').mockImplementation(jest.fn()); | ||
}); | ||
|
||
afterEach(() => { | ||
Check warning on line 12 in lib/lang/validator.spec.js GitHub Actions / build (16.x, ubuntu-latest)
|
||
jest.restoreAllMocks(); | ||
}); | ||
|
||
describe('valid', () => { | ||
it('run with no errors', async () => { | ||
const themePath = path.join( | ||
Check warning on line 18 in lib/lang/validator.spec.js GitHub Actions / build (16.x, ubuntu-latest)
|
||
process.cwd(), | ||
'test/_mocks/themes/valid', | ||
); | ||
const validator = new LangFilesValidator(themePath); | ||
const errors = await validator.run(); | ||
|
||
expect(errors.length).toEqual(0); | ||
Check failure on line 25 in lib/lang/validator.spec.js GitHub Actions / build (16.x, ubuntu-latest)
|
||
}); | ||
|
||
it('run with no errors', async () => { | ||
Check failure on line 28 in lib/lang/validator.spec.js GitHub Actions / build (16.x, ubuntu-latest)
|
||
const themePath = path.join( | ||
Check warning on line 29 in lib/lang/validator.spec.js GitHub Actions / build (16.x, ubuntu-latest)
|
||
process.cwd(), | ||
'test/_mocks/themes/valid', | ||
); | ||
const validator = new LangFilesValidator(themePath); | ||
const errors = await validator.run("en"); | ||
Check warning on line 34 in lib/lang/validator.spec.js GitHub Actions / build (16.x, ubuntu-latest)
|
||
|
||
expect(errors.length).toEqual(0); | ||
}); | ||
}); | ||
|
||
describe('not valid', () => { | ||
it('run with no fr lang file', async () => { | ||
const themePath = path.join( | ||
process.cwd(), | ||
'test/_mocks/themes/invalid-translations', | ||
); | ||
const validator = new LangFilesValidator(themePath); | ||
const errors = await validator.run(); | ||
|
||
expect(errors.length).toEqual(1); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
{ | ||
"header": { | ||
"welcome_back": "Welcome back, {name}" | ||
}, | ||
"footer": { | ||
"brands": "Popular Brands", | ||
"navigate": "Navigate", | ||
"info": "Info", | ||
"categories": "Categories", | ||
"call_us": "Call us at {phone_number}" | ||
}, | ||
"home": { | ||
"heading": "Home" | ||
}, | ||
"blog": { | ||
"recent_posts": "Recent Posts", | ||
"label": "Blog", | ||
"posted_by": "Posted by {name}" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
a |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
b | ||
|
||
|
||
<!-- test | ||
{{{stylesheet '/assets/custom/css/test.css'}}} --> | ||
|
||
more text here |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>page.html</title> | ||
</head> | ||
<body> | ||
{{ lang 'failed' }} | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>page2.html</title> | ||
{{head.scripts}} | ||
</head> | ||
<body> | ||
<h1>{{theme_settings.customizable_title}}</h1> | ||
{{> components/b}} | ||
{{footer.scripts}} | ||
</body> | ||
</html> |