Skip to content

Commit 9e6d6e1

Browse files
committed
feat: Add loader for php files.
1 parent f83be4b commit 9e6d6e1

File tree

6 files changed

+143
-0
lines changed

6 files changed

+143
-0
lines changed

package-lock.json

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

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"typescript": "^4.6.2"
3636
},
3737
"dependencies": {
38+
"php-parser": "^3.1.0-beta.4",
3839
"vue": "^3.2.31"
3940
},
4041
"lint-staged": {

src/loader.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import fs from 'fs';
2+
import path from 'path';
3+
import { Engine } from 'php-parser';
4+
5+
export const parseAll = (folderPath: string): { name: string, path: string }[] => {
6+
folderPath = folderPath.replace(/[\\/]$/, '') + path.sep;
7+
8+
const folders = fs.readdirSync(folderPath)
9+
.filter(file => fs.statSync(folderPath + path.sep + file).isDirectory())
10+
.sort();
11+
12+
const data = [];
13+
for (const folder of folders) {
14+
const lang = {};
15+
16+
fs
17+
.readdirSync(folderPath + path.sep + folder)
18+
.filter(file => ! fs.statSync(folderPath + path.sep + folder + path.sep + file).isDirectory())
19+
.sort()
20+
.forEach((file) => {
21+
lang[file.replace(/\.\w+$/, '')] = parse(fs.readFileSync(folderPath + path.sep + folder + path.sep + file).toString());
22+
});
23+
24+
data.push({
25+
folder,
26+
translations: convertToDotsSyntax(lang),
27+
});
28+
}
29+
30+
return data.map(({ folder, translations }) => {
31+
const name = `php_${folder}.json`;
32+
const path = folderPath + name;
33+
34+
fs.writeFileSync(path, JSON.stringify(translations));
35+
return { name, path }
36+
});
37+
}
38+
39+
export const parse = (content: string) => {
40+
const arr = (new Engine({})).parseCode(content, 'lang').children
41+
.filter(child => child.kind === 'return')[0] as any;
42+
43+
return parseItem(arr.expr);
44+
}
45+
46+
const parseItem = (expr) => {
47+
if (expr.kind === 'string') {
48+
return expr.value;
49+
}
50+
51+
if (expr.kind === 'array') {
52+
let items = expr.items.map((item) => parseItem(item));
53+
54+
if (expr.items.every((item) => item.key !== null)) {
55+
items = items.reduce((acc, val) => Object.assign({}, acc, val), {})
56+
}
57+
58+
return items;
59+
}
60+
61+
if (expr.key) {
62+
return { [expr.key.value]: parseItem(expr.value) }
63+
}
64+
65+
return parseItem(expr.value)
66+
}
67+
68+
const convertToDotsSyntax = (list) => {
69+
const flatten = (items, context = '') => {
70+
const data = {};
71+
72+
Object.entries(items).forEach(([key, value]) => {
73+
if (typeof value === 'string') {
74+
data[context + key] = value;
75+
return;
76+
}
77+
78+
Object.entries(flatten(value, context + key + '.')).forEach(([itemKey, itemValue]) => {
79+
data[itemKey] = itemValue;
80+
});
81+
});
82+
83+
return data;
84+
}
85+
86+
return flatten(list);
87+
}

test/fixtures/lang/en/auth.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?php
2+
3+
return [
4+
'failed' => 'These credentials do not match our records.',
5+
'password' => 'The provided password is incorrect.',
6+
];

test/fixtures/lang/pt/auth.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?php
2+
3+
return [
4+
'failed' => 'As credenciais indicadas não coincidem com as registadas no sistema.',
5+
'password' => 'A palavra-passe indicada está incorreta.',
6+
];

test/loader.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import fs from 'fs';
2+
import path from 'path';
3+
import { parseAll, parse } from '../src/loader';
4+
5+
beforeEach(() => {
6+
const folderPath = __dirname + '/fixtures/lang/';
7+
const dir = fs.readdirSync(folderPath);
8+
9+
dir.filter(file => file.match(/^php_/)).forEach(file => {
10+
fs.unlinkSync(folderPath + file);
11+
});
12+
});
13+
14+
it('creates a file for each lang', () => {
15+
const files = parseAll(__dirname + '/fixtures/lang/');
16+
17+
expect(files.length).toBe(2);
18+
expect(files[0].name).toBe('php_en.json');
19+
expect(files[1].name).toBe('php_pt.json');
20+
21+
const langEn = JSON.parse(fs.readFileSync(files[0].path).toString());
22+
expect(langEn['auth.failed']).toBe('These credentials do not match our records.');
23+
24+
const langPt = JSON.parse(fs.readFileSync(files[1].path).toString());
25+
expect(langPt['auth.failed']).toBe('As credenciais indicadas não coincidem com as registadas no sistema.');
26+
});
27+
28+
it('transforms .php lang to .json', () => {
29+
const lang = parse(fs.readFileSync(__dirname + '/fixtures/lang/en/auth.php').toString());
30+
31+
expect(lang['failed']).toBe('These credentials do not match our records.');
32+
});

0 commit comments

Comments
 (0)