@cemalidev/trate 1.4.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/.env.example +16 -0
- package/.github/workflows/ci.yml +61 -0
- package/.github/workflows/cleanup.yml +36 -0
- package/.github/workflows/release.yml +56 -0
- package/.husky/pre-commit +4 -0
- package/.prettierrc +10 -0
- package/CHANGELOG.md +40 -0
- package/CONTRIBUTING.md +120 -0
- package/LICENSE +21 -0
- package/README.md +140 -0
- package/build.cjs +27 -0
- package/dist/index.js +1587 -0
- package/eslint.config.mjs +42 -0
- package/package.json +67 -0
- package/src/config/config.ts +130 -0
- package/src/config/types.ts +9 -0
- package/src/convert.ts +562 -0
- package/src/dashboard.ts +76 -0
- package/src/i18n/de.ts +90 -0
- package/src/i18n/en.ts +94 -0
- package/src/i18n/es.ts +90 -0
- package/src/i18n/fr.ts +90 -0
- package/src/i18n/index.ts +108 -0
- package/src/i18n/tr.ts +90 -0
- package/src/index.ts +390 -0
- package/src/logo.ts +33 -0
- package/src/types/errors.ts +38 -0
- package/src/ui.ts +40 -0
- package/src/utils/logger.ts +84 -0
- package/tests/config.test.ts +95 -0
- package/tests/i18n.test.ts +121 -0
- package/tests/validation.test.ts +149 -0
- package/tsconfig.json +18 -0
- package/vitest.config.ts +15 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { describe, it, expect, afterEach } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
t,
|
|
4
|
+
setLocale,
|
|
5
|
+
getLocale,
|
|
6
|
+
resetLocale,
|
|
7
|
+
getSupportedLocales,
|
|
8
|
+
getLocaleDisplayName,
|
|
9
|
+
Locale,
|
|
10
|
+
} from '../src/i18n';
|
|
11
|
+
|
|
12
|
+
describe('i18n', () => {
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
resetLocale();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe('getLocale', () => {
|
|
18
|
+
it('should return a supported locale', () => {
|
|
19
|
+
const locale = getLocale();
|
|
20
|
+
expect(getSupportedLocales()).toContain(locale);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe('setLocale', () => {
|
|
25
|
+
it('should change the current locale', () => {
|
|
26
|
+
setLocale('tr');
|
|
27
|
+
expect(getLocale()).toBe('tr');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should throw error for unsupported locale', () => {
|
|
31
|
+
expect(() => setLocale('xx' as Locale)).toThrow();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should persist locale across multiple calls', () => {
|
|
35
|
+
setLocale('de');
|
|
36
|
+
setLocale('fr');
|
|
37
|
+
expect(getLocale()).toBe('fr');
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe('resetLocale', () => {
|
|
42
|
+
it('should reset to system locale', () => {
|
|
43
|
+
setLocale('tr');
|
|
44
|
+
resetLocale();
|
|
45
|
+
const locale = getLocale();
|
|
46
|
+
expect(getSupportedLocales()).toContain(locale);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe('getSupportedLocales', () => {
|
|
51
|
+
it('should return all supported locales', () => {
|
|
52
|
+
const locales = getSupportedLocales();
|
|
53
|
+
expect(locales).toContain('tr');
|
|
54
|
+
expect(locales).toContain('en');
|
|
55
|
+
expect(locales).toContain('de');
|
|
56
|
+
expect(locales).toContain('fr');
|
|
57
|
+
expect(locales).toContain('es');
|
|
58
|
+
expect(locales.length).toBe(5);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('getLocaleDisplayName', () => {
|
|
63
|
+
it('should return display name for supported locales', () => {
|
|
64
|
+
expect(getLocaleDisplayName('tr')).toBe('Türkçe');
|
|
65
|
+
expect(getLocaleDisplayName('en')).toBe('English');
|
|
66
|
+
expect(getLocaleDisplayName('de')).toBe('Deutsch');
|
|
67
|
+
expect(getLocaleDisplayName('fr')).toBe('Français');
|
|
68
|
+
expect(getLocaleDisplayName('es')).toBe('Español');
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe('t()', () => {
|
|
73
|
+
it('should return translation for Turkish', () => {
|
|
74
|
+
setLocale('tr');
|
|
75
|
+
expect(t('error.noConnection')).toBe('İnternet bağlantınızı kontrol ediniz');
|
|
76
|
+
expect(t('success.added')).toBe('Eklendi');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should return translation for English', () => {
|
|
80
|
+
setLocale('en');
|
|
81
|
+
expect(t('error.noConnection')).toBe('Check your internet connection');
|
|
82
|
+
expect(t('success.added')).toBe('Added');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should return translation for German', () => {
|
|
86
|
+
setLocale('de');
|
|
87
|
+
expect(t('error.noConnection')).toBe('Überprüfen Sie Ihre Internetverbindung');
|
|
88
|
+
expect(t('success.added')).toBe('Hinzugefügt');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should return translation for French', () => {
|
|
92
|
+
setLocale('fr');
|
|
93
|
+
expect(t('error.noConnection')).toBe('Vérifiez votre connexion internet');
|
|
94
|
+
expect(t('success.added')).toBe('Ajouté');
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should return translation for Spanish', () => {
|
|
98
|
+
setLocale('es');
|
|
99
|
+
expect(t('error.noConnection')).toBe('Verifica tu conexión a internet');
|
|
100
|
+
expect(t('success.added')).toBe('Añadido');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('should fallback to English for missing translation', () => {
|
|
104
|
+
setLocale('tr');
|
|
105
|
+
const result = t('error.noConnection' as any);
|
|
106
|
+
expect(typeof result).toBe('string');
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('should handle nested keys', () => {
|
|
110
|
+
setLocale('en');
|
|
111
|
+
expect(t('dashboard.type.fiat')).toBe('FIAT');
|
|
112
|
+
expect(t('dashboard.type.crypto')).toBe('CRYPTO');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should return key if translation not found', () => {
|
|
116
|
+
setLocale('en');
|
|
117
|
+
const result = t('nonexistent.key' as any);
|
|
118
|
+
expect(result).toBe('nonexistent.key');
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
});
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { describe, it, expect, afterEach } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
isCrypto,
|
|
4
|
+
isMetal,
|
|
5
|
+
isJewelry,
|
|
6
|
+
isFiat,
|
|
7
|
+
getCryptoList,
|
|
8
|
+
getMetalList,
|
|
9
|
+
getJewelryList,
|
|
10
|
+
getFiatList,
|
|
11
|
+
getDisplayName,
|
|
12
|
+
} from '../src/convert';
|
|
13
|
+
import { setLocale, resetLocale } from '../src/i18n';
|
|
14
|
+
|
|
15
|
+
describe('Currency Validation', () => {
|
|
16
|
+
describe('isCrypto', () => {
|
|
17
|
+
it('should identify crypto currencies', () => {
|
|
18
|
+
expect(isCrypto('BTC')).toBe(true);
|
|
19
|
+
expect(isCrypto('ETH')).toBe(true);
|
|
20
|
+
expect(isCrypto('btc')).toBe(true);
|
|
21
|
+
expect(isCrypto('Sol')).toBe(true);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should reject non-crypto currencies', () => {
|
|
25
|
+
expect(isCrypto('USD')).toBe(false);
|
|
26
|
+
expect(isCrypto('ONS')).toBe(false);
|
|
27
|
+
expect(isCrypto('CEYREK_ALTIN')).toBe(false);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should reject invalid symbols', () => {
|
|
31
|
+
expect(isCrypto('INVALID')).toBe(false);
|
|
32
|
+
expect(isCrypto('')).toBe(false);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe('isMetal', () => {
|
|
37
|
+
it('should identify metal symbols', () => {
|
|
38
|
+
expect(isMetal('ONS')).toBe(true);
|
|
39
|
+
expect(isMetal('GUMUS_OZ')).toBe(true);
|
|
40
|
+
expect(isMetal('ons')).toBe(true);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should reject non-metal symbols', () => {
|
|
44
|
+
expect(isMetal('BTC')).toBe(false);
|
|
45
|
+
expect(isMetal('USD')).toBe(false);
|
|
46
|
+
expect(isMetal('CEYREK_ALTIN')).toBe(false);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe('isJewelry', () => {
|
|
51
|
+
it('should identify jewelry symbols', () => {
|
|
52
|
+
expect(isJewelry('CEYREK_ALTIN')).toBe(true);
|
|
53
|
+
expect(isJewelry('YARIM_ALTIN')).toBe(true);
|
|
54
|
+
expect(isJewelry('TAM_ALTIN')).toBe(true);
|
|
55
|
+
expect(isJewelry('ATA_ALTIN')).toBe(true);
|
|
56
|
+
expect(isJewelry('ceyrek_altin')).toBe(true);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should reject non-jewelry symbols', () => {
|
|
60
|
+
expect(isJewelry('BTC')).toBe(false);
|
|
61
|
+
expect(isJewelry('USD')).toBe(false);
|
|
62
|
+
expect(isJewelry('ONS')).toBe(false);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe('isFiat', () => {
|
|
67
|
+
it('should identify fiat currencies', () => {
|
|
68
|
+
expect(isFiat('USD')).toBe(true);
|
|
69
|
+
expect(isFiat('EUR')).toBe(true);
|
|
70
|
+
expect(isFiat('TRY')).toBe(true);
|
|
71
|
+
expect(isFiat('usd')).toBe(true);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should reject non-fiat symbols', () => {
|
|
75
|
+
expect(isFiat('BTC')).toBe(false);
|
|
76
|
+
expect(isFiat('ONS')).toBe(false);
|
|
77
|
+
expect(isFiat('CEYREK_ALTIN')).toBe(false);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe('Currency Lists', () => {
|
|
83
|
+
describe('getCryptoList', () => {
|
|
84
|
+
it('should return array of crypto symbols', () => {
|
|
85
|
+
const list = getCryptoList();
|
|
86
|
+
expect(Array.isArray(list)).toBe(true);
|
|
87
|
+
expect(list.length).toBeGreaterThan(0);
|
|
88
|
+
expect(list).toContain('BTC');
|
|
89
|
+
expect(list).toContain('ETH');
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe('getMetalList', () => {
|
|
94
|
+
it('should return array of metal symbols', () => {
|
|
95
|
+
const list = getMetalList();
|
|
96
|
+
expect(Array.isArray(list)).toBe(true);
|
|
97
|
+
expect(list).toContain('ONS');
|
|
98
|
+
expect(list).toContain('GUMUS_OZ');
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe('getJewelryList', () => {
|
|
103
|
+
it('should return array of jewelry symbols', () => {
|
|
104
|
+
const list = getJewelryList();
|
|
105
|
+
expect(Array.isArray(list)).toBe(true);
|
|
106
|
+
expect(list).toContain('CEYREK_ALTIN');
|
|
107
|
+
expect(list).toContain('TAM_ALTIN');
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe('getFiatList', () => {
|
|
112
|
+
it('should return array of fiat symbols', () => {
|
|
113
|
+
const list = getFiatList();
|
|
114
|
+
expect(Array.isArray(list)).toBe(true);
|
|
115
|
+
expect(list).toContain('USD');
|
|
116
|
+
expect(list).toContain('EUR');
|
|
117
|
+
expect(list).toContain('TRY');
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe('Display Names', () => {
|
|
123
|
+
afterEach(() => {
|
|
124
|
+
resetLocale();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('should return Turkish display names when locale is TR', () => {
|
|
128
|
+
setLocale('tr');
|
|
129
|
+
expect(getDisplayName('ONS')).toBe('Altın Ons');
|
|
130
|
+
expect(getDisplayName('CEYREK_ALTIN')).toBe('Çeyrek Altın');
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should return English display names when locale is EN', () => {
|
|
134
|
+
setLocale('en');
|
|
135
|
+
expect(getDisplayName('ONS')).toBe('Gold Ounce');
|
|
136
|
+
expect(getDisplayName('CEYREK_ALTIN')).toBe('Quarter Gold');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should return German display names when locale is DE', () => {
|
|
140
|
+
setLocale('de');
|
|
141
|
+
expect(getDisplayName('ONS')).toBe('Gold Unze');
|
|
142
|
+
expect(getDisplayName('CEYREK_ALTIN')).toBe('Viertel Gold');
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should return unknown symbol as-is', () => {
|
|
146
|
+
setLocale('en');
|
|
147
|
+
expect(getDisplayName('UNKNOWN')).toBe('UNKNOWN');
|
|
148
|
+
});
|
|
149
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"rootDir": "./src",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"declaration": false
|
|
15
|
+
},
|
|
16
|
+
"include": ["src/**/*"],
|
|
17
|
+
"exclude": ["node_modules", "dist"]
|
|
18
|
+
}
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
globals: true,
|
|
6
|
+
environment: 'node',
|
|
7
|
+
include: ['tests/**/*.test.ts'],
|
|
8
|
+
coverage: {
|
|
9
|
+
provider: 'v8',
|
|
10
|
+
reporter: ['text', 'json', 'html'],
|
|
11
|
+
include: ['src/**/*.ts'],
|
|
12
|
+
exclude: ['src/index.ts', 'src/logo.ts', 'src/ui.ts'],
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
});
|