@xxanderwp/translate-module 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -0
- package/dist/index.js +22 -3
- package/package.json +1 -1
- package/.github/workflows/deploy.yml +0 -64
- package/.github/workflows/test.yml +0 -46
- package/jest.config.js +0 -30
- package/src/index.ts +0 -64
- package/tests/index.test.ts +0 -79
- package/tsconfig.json +0 -17
- package/tsconfig.test.json +0 -11
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export declare class LanguageCore<T extends Record<string, Record<string, string
|
|
|
2
2
|
private readonly _languages_data;
|
|
3
3
|
private _currentLanguage;
|
|
4
4
|
constructor(data: T, defaultLanguage?: keyof T);
|
|
5
|
+
private validateLanguageData;
|
|
5
6
|
get languagesData(): T;
|
|
6
7
|
get currentLanguage(): LangKey | null;
|
|
7
8
|
set currentLanguage(lang: LangKey);
|
package/dist/index.js
CHANGED
|
@@ -4,9 +4,7 @@ exports.LanguageCore = void 0;
|
|
|
4
4
|
class LanguageCore {
|
|
5
5
|
constructor(data, defaultLanguage) {
|
|
6
6
|
this._currentLanguage = null;
|
|
7
|
-
|
|
8
|
-
throw new Error("Languages data cannot be empty.");
|
|
9
|
-
}
|
|
7
|
+
this.validateLanguageData(data);
|
|
10
8
|
this._languages_data = data;
|
|
11
9
|
if (defaultLanguage) {
|
|
12
10
|
if (!this.langKeys.includes(defaultLanguage)) {
|
|
@@ -18,6 +16,27 @@ class LanguageCore {
|
|
|
18
16
|
this._currentLanguage = Object.keys(data)[0];
|
|
19
17
|
}
|
|
20
18
|
}
|
|
19
|
+
validateLanguageData(data) {
|
|
20
|
+
if (Object.keys(data).length === 0) {
|
|
21
|
+
throw new Error("Languages data cannot be empty.");
|
|
22
|
+
}
|
|
23
|
+
const firstLangData = data[Object.keys(data)[0]];
|
|
24
|
+
if (typeof firstLangData !== "object" || Array.isArray(firstLangData)) {
|
|
25
|
+
throw new Error("Each language data must be an object.");
|
|
26
|
+
}
|
|
27
|
+
const firstLangKeys = Object.keys(firstLangData);
|
|
28
|
+
for (const langKey in data) {
|
|
29
|
+
const langData = data[langKey];
|
|
30
|
+
if (typeof langData !== "object" || Array.isArray(langData)) {
|
|
31
|
+
throw new Error(`Language data for ${langKey} must be an object.`);
|
|
32
|
+
}
|
|
33
|
+
const langKeys = Object.keys(langData);
|
|
34
|
+
if (langKeys.length !== firstLangKeys.length ||
|
|
35
|
+
!langKeys.every((key) => firstLangKeys.includes(key))) {
|
|
36
|
+
throw new Error(`All languages must have the same keys. Mismatch found in ${langKey}.`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
21
40
|
get languagesData() {
|
|
22
41
|
return this._languages_data;
|
|
23
42
|
}
|
package/package.json
CHANGED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
name: Publish npm Package
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [main, beta]
|
|
6
|
-
|
|
7
|
-
jobs:
|
|
8
|
-
publish:
|
|
9
|
-
runs-on: ubuntu-latest
|
|
10
|
-
steps:
|
|
11
|
-
- name: Checkout repository
|
|
12
|
-
uses: actions/checkout@v3
|
|
13
|
-
|
|
14
|
-
- name: Setup Node.js
|
|
15
|
-
uses: actions/setup-node@v3
|
|
16
|
-
with:
|
|
17
|
-
node-version: 20
|
|
18
|
-
registry-url: https://registry.npmjs.org/
|
|
19
|
-
|
|
20
|
-
- name: Install dependencies
|
|
21
|
-
run: npm ci
|
|
22
|
-
|
|
23
|
-
- name: Build package
|
|
24
|
-
run: npm run build
|
|
25
|
-
|
|
26
|
-
- name: Check if version exists on npm
|
|
27
|
-
id: check_version
|
|
28
|
-
run: |
|
|
29
|
-
PACKAGE_NAME=$(node -p "require('./package.json').name")
|
|
30
|
-
PACKAGE_VERSION=$(node -p "require('./package.json').version")
|
|
31
|
-
echo "Package: $PACKAGE_NAME"
|
|
32
|
-
echo "Version: $PACKAGE_VERSION"
|
|
33
|
-
|
|
34
|
-
# Проверяем, есть ли уже такая версия на npm
|
|
35
|
-
if npm view "$PACKAGE_NAME@$PACKAGE_VERSION" >/dev/null 2>&1; then
|
|
36
|
-
echo "Version $PACKAGE_VERSION already exists on npm"
|
|
37
|
-
echo "exists=true" >> $GITHUB_OUTPUT
|
|
38
|
-
else
|
|
39
|
-
echo "Version $PACKAGE_VERSION is new"
|
|
40
|
-
echo "exists=false" >> $GITHUB_OUTPUT
|
|
41
|
-
fi
|
|
42
|
-
|
|
43
|
-
- name: Publish to npm (latest)
|
|
44
|
-
if: steps.check_version.outputs.exists == 'false' && github.ref == 'refs/heads/main'
|
|
45
|
-
env:
|
|
46
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
47
|
-
run: |
|
|
48
|
-
npm publish --access=public
|
|
49
|
-
|
|
50
|
-
- name: Mark existing version as latest
|
|
51
|
-
if: steps.check_version.outputs.exists == 'true' && github.ref == 'refs/heads/main'
|
|
52
|
-
env:
|
|
53
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
54
|
-
run: |
|
|
55
|
-
PACKAGE_NAME=$(node -p "require('./package.json').name")
|
|
56
|
-
PACKAGE_VERSION=$(node -p "require('./package.json').version")
|
|
57
|
-
npm dist-tag add "$PACKAGE_NAME@$PACKAGE_VERSION" latest
|
|
58
|
-
|
|
59
|
-
- name: Publish to npm (beta)
|
|
60
|
-
if: steps.check_version.outputs.exists == 'false' && github.ref == 'refs/heads/beta'
|
|
61
|
-
env:
|
|
62
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
63
|
-
run: |
|
|
64
|
-
npm publish --tag beta --access=public
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
name: Tests
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [develop]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [main, beta, develop]
|
|
8
|
-
|
|
9
|
-
jobs:
|
|
10
|
-
test:
|
|
11
|
-
runs-on: ubuntu-latest
|
|
12
|
-
|
|
13
|
-
strategy:
|
|
14
|
-
matrix:
|
|
15
|
-
node-version: [16.x, 18.x, 20.x, 22.x]
|
|
16
|
-
|
|
17
|
-
steps:
|
|
18
|
-
- uses: actions/checkout@v3
|
|
19
|
-
|
|
20
|
-
- name: Use Node.js ${{ matrix.node-version }}
|
|
21
|
-
uses: actions/setup-node@v3
|
|
22
|
-
with:
|
|
23
|
-
node-version: ${{ matrix.node-version }}
|
|
24
|
-
|
|
25
|
-
- name: Install dependencies
|
|
26
|
-
run: npm ci
|
|
27
|
-
|
|
28
|
-
- name: Run linter
|
|
29
|
-
run: npm run lint
|
|
30
|
-
|
|
31
|
-
- name: Run tests
|
|
32
|
-
run: npm test
|
|
33
|
-
|
|
34
|
-
- name: Run coverage
|
|
35
|
-
run: npm run test:coverage
|
|
36
|
-
|
|
37
|
-
- name: Upload coverage to Codecov
|
|
38
|
-
uses: codecov/codecov-action@v3
|
|
39
|
-
if: matrix.node-version == '22.x'
|
|
40
|
-
with:
|
|
41
|
-
file: ./coverage/lcov.info
|
|
42
|
-
flags: unittests
|
|
43
|
-
name: codecov-umbrella
|
|
44
|
-
|
|
45
|
-
- name: Build
|
|
46
|
-
run: npm run build
|
package/jest.config.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
preset: 'ts-jest',
|
|
3
|
-
testEnvironment: 'node',
|
|
4
|
-
roots: ['<rootDir>/src', '<rootDir>/tests'],
|
|
5
|
-
testMatch: ['**/__tests__/**/*.ts', '**/?(*.)+(spec|test).ts'],
|
|
6
|
-
testTimeout: 10000,
|
|
7
|
-
collectCoverageFrom: [
|
|
8
|
-
'src/**/*.ts',
|
|
9
|
-
'!src/**/*.d.ts',
|
|
10
|
-
'!src/**/*.test.ts',
|
|
11
|
-
'!src/**/*.spec.ts',
|
|
12
|
-
],
|
|
13
|
-
coverageThreshold: {
|
|
14
|
-
global: {
|
|
15
|
-
branches: 50,
|
|
16
|
-
functions: 50,
|
|
17
|
-
lines: 50,
|
|
18
|
-
statements: 50,
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
moduleFileExtensions: ['ts', 'js', 'json'],
|
|
22
|
-
transform: {
|
|
23
|
-
'^.+\\.ts$': [
|
|
24
|
-
'ts-jest',
|
|
25
|
-
{
|
|
26
|
-
tsconfig: 'tsconfig.test.json',
|
|
27
|
-
},
|
|
28
|
-
],
|
|
29
|
-
},
|
|
30
|
-
};
|
package/src/index.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
export class LanguageCore<
|
|
2
|
-
T extends Record<string, Record<string, string>>,
|
|
3
|
-
LangKey extends keyof T = keyof T
|
|
4
|
-
> {
|
|
5
|
-
private readonly _languages_data: T;
|
|
6
|
-
private _currentLanguage: LangKey | null = null;
|
|
7
|
-
|
|
8
|
-
constructor(data: T, defaultLanguage?: keyof T) {
|
|
9
|
-
if (Object.keys(data).length === 0) {
|
|
10
|
-
throw new Error("Languages data cannot be empty.");
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
this._languages_data = data;
|
|
14
|
-
if(defaultLanguage) {
|
|
15
|
-
if (!this.langKeys.includes(defaultLanguage as LangKey)) {
|
|
16
|
-
throw new Error(`Default language ${String(defaultLanguage)} is not supported.`);
|
|
17
|
-
}
|
|
18
|
-
this._currentLanguage = defaultLanguage as LangKey;
|
|
19
|
-
} else {
|
|
20
|
-
this._currentLanguage = Object.keys(data)[0] as LangKey;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
get languagesData(): T {
|
|
25
|
-
return this._languages_data;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
get currentLanguage(): LangKey | null {
|
|
29
|
-
return this._currentLanguage;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
set currentLanguage(lang: LangKey) {
|
|
33
|
-
if (!this.langKeys.includes(lang)) {
|
|
34
|
-
throw new Error(`Language ${String(lang)} is not supported.`);
|
|
35
|
-
}
|
|
36
|
-
this._currentLanguage = lang;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
get langKeys(): LangKey[] {
|
|
40
|
-
return Object.keys(this._languages_data) as LangKey[];
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
get currentLanguageData(): T[LangKey] | null {
|
|
44
|
-
if (!this._currentLanguage) return null;
|
|
45
|
-
return this._languages_data[this._currentLanguage];
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
translate<K extends keyof T[LangKey]>(
|
|
49
|
-
key: K,
|
|
50
|
-
...args: (string | number)[]
|
|
51
|
-
): string | null {
|
|
52
|
-
if (!this._currentLanguage) return null;
|
|
53
|
-
|
|
54
|
-
const langData = this._languages_data[this._currentLanguage];
|
|
55
|
-
let res = langData[key] as string;
|
|
56
|
-
|
|
57
|
-
args.forEach((arg, index) => {
|
|
58
|
-
res = res.replace(new RegExp(`\\{${index}\\}`, "g"), String(arg));
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
return res || null;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
package/tests/index.test.ts
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "@jest/globals";
|
|
2
|
-
import { LanguageCore } from "../src/index";
|
|
3
|
-
|
|
4
|
-
describe("LangModule", () => {
|
|
5
|
-
it("should initialize with valid data and default language", () => {
|
|
6
|
-
const data = {
|
|
7
|
-
en: { greeting: "Hello" },
|
|
8
|
-
es: { greeting: "Hola" },
|
|
9
|
-
};
|
|
10
|
-
const langModule = new LanguageCore(data, "es");
|
|
11
|
-
expect(langModule.languagesData).toEqual(data);
|
|
12
|
-
expect(langModule.currentLanguage).toBe("es");
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it("should throw an error if initialized with empty data", () => {
|
|
16
|
-
expect(() => new LanguageCore({})).toThrow("Languages data cannot be empty.");
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it("should throw an error if default language is not supported", () => {
|
|
20
|
-
const data = {
|
|
21
|
-
en: { greeting: "Hello" },
|
|
22
|
-
es: { greeting: "Hola" },
|
|
23
|
-
};
|
|
24
|
-
// @ts-ignore
|
|
25
|
-
expect(() => new LanguageCore(data, "fr")).toThrow("Default language fr is not supported.");
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it("should return the correct translation for the current language", () => {
|
|
29
|
-
const data = {
|
|
30
|
-
en: { greeting: "Hello, {0}!" },
|
|
31
|
-
es: { greeting: "¡Hola, {0}!" },
|
|
32
|
-
};
|
|
33
|
-
const langModule = new LanguageCore(data, "en");
|
|
34
|
-
expect(langModule.translate("greeting", "John")).toBe("Hello, John!");
|
|
35
|
-
langModule.currentLanguage = "es";
|
|
36
|
-
expect(langModule.translate("greeting", "John")).toBe("¡Hola, John!");
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it("should throw an error when setting an unsupported language", () => {
|
|
40
|
-
const data = {
|
|
41
|
-
en: { greeting: "Hello" },
|
|
42
|
-
es: { greeting: "Hola" },
|
|
43
|
-
};
|
|
44
|
-
const langModule = new LanguageCore(data);
|
|
45
|
-
// @ts-ignore
|
|
46
|
-
expect(() => (langModule.currentLanguage = "fr")).toThrow("Language fr is not supported.");
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it("should return null for translation if current language is not set", () => {
|
|
50
|
-
const data = {
|
|
51
|
-
en: { greeting: "Hello" },
|
|
52
|
-
es: { greeting: "Hola" },
|
|
53
|
-
};
|
|
54
|
-
const langModule = new LanguageCore(data);
|
|
55
|
-
// @ts-ignore
|
|
56
|
-
expect(() => (langModule.currentLanguage = null)).toThrow("Language null is not supported.");
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it("should return null for translation if key does not exist", () => {
|
|
60
|
-
const data = {
|
|
61
|
-
en: { greeting: "Hello" },
|
|
62
|
-
es: { greeting: "Hola" },
|
|
63
|
-
};
|
|
64
|
-
const langModule = new LanguageCore(data);
|
|
65
|
-
// @ts-ignore
|
|
66
|
-
expect(langModule.translate("farewell")).toBeNull();
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it("should return the correct language keys", () => {
|
|
70
|
-
const data = {
|
|
71
|
-
en: { greeting: "Hello" },
|
|
72
|
-
es: { greeting: "Hola" },
|
|
73
|
-
};
|
|
74
|
-
const langModule = new LanguageCore(data);
|
|
75
|
-
expect(langModule.langKeys).toEqual(["en", "es"]);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
});
|
package/tsconfig.json
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"declaration": true,
|
|
4
|
-
"target": "ES2020",
|
|
5
|
-
"module": "CommonJS",
|
|
6
|
-
"lib": ["ES2020", "DOM"],
|
|
7
|
-
"strict": true,
|
|
8
|
-
"esModuleInterop": true,
|
|
9
|
-
"skipLibCheck": true,
|
|
10
|
-
"resolveJsonModule": true,
|
|
11
|
-
"outDir": "./dist",
|
|
12
|
-
"rootDir": "./src",
|
|
13
|
-
"types": ["node"]
|
|
14
|
-
},
|
|
15
|
-
"include": ["src/**/*"],
|
|
16
|
-
"exclude": ["node_modules", "dist"]
|
|
17
|
-
}
|
package/tsconfig.test.json
DELETED