afro-locale 0.1.0
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/API.md +390 -0
- package/CHANGELOG.md +73 -0
- package/CODE_OF_CONDUCT.md +96 -0
- package/CONTRIBUTING.md +351 -0
- package/EXAMPLES.md +327 -0
- package/LICENSE +21 -0
- package/README.md +431 -0
- package/SECURITY.md +84 -0
- package/SUPPORT.md +264 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +167 -0
- package/dist/index.js.map +1 -0
- package/package.json +61 -0
package/SUPPORT.md
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# Support & Get Help
|
|
2
|
+
|
|
3
|
+
Thank you for using `@koadit/afro-locale`! We're here to help if you have questions or run into issues.
|
|
4
|
+
|
|
5
|
+
## 📚 Documentation
|
|
6
|
+
|
|
7
|
+
- **[README.md](README.md)** - Overview and quick start guide
|
|
8
|
+
- **[API.md](API.md)** - Detailed API reference and usage patterns
|
|
9
|
+
- **[CONTRIBUTING.md](CONTRIBUTING.md)** - How to contribute to the project
|
|
10
|
+
- **[CHANGELOG.md](CHANGELOG.md)** - Version history and updates
|
|
11
|
+
|
|
12
|
+
## 🆘 Getting Help
|
|
13
|
+
|
|
14
|
+
### I Have a Question
|
|
15
|
+
|
|
16
|
+
**GitHub Discussions** (Recommended)
|
|
17
|
+
- Visit: [GitHub Discussions](https://github.com/oluokunkabiru/afro-locale/discussions)
|
|
18
|
+
- Ask questions in the Q&A category
|
|
19
|
+
- Browse existing questions for common issues
|
|
20
|
+
|
|
21
|
+
**Email**
|
|
22
|
+
- General inquiries: info@koadit.com
|
|
23
|
+
- Technical questions: support@koadit.com
|
|
24
|
+
|
|
25
|
+
### I Found a Bug
|
|
26
|
+
|
|
27
|
+
**GitHub Issues**
|
|
28
|
+
1. Check [existing issues](https://github.com/oluokunkabiru/afro-locale/issues) to avoid duplicates
|
|
29
|
+
2. [Create a new issue](https://github.com/oluokunkabiru/afro-locale/issues/new) with:
|
|
30
|
+
- Clear title describing the bug
|
|
31
|
+
- Steps to reproduce
|
|
32
|
+
- Expected behavior
|
|
33
|
+
- Actual behavior
|
|
34
|
+
- Browser/Node.js version
|
|
35
|
+
- Code example if possible
|
|
36
|
+
|
|
37
|
+
**Bug Report Template:**
|
|
38
|
+
```markdown
|
|
39
|
+
## Description
|
|
40
|
+
Brief description of the bug
|
|
41
|
+
|
|
42
|
+
## Steps to Reproduce
|
|
43
|
+
1. Step 1
|
|
44
|
+
2. Step 2
|
|
45
|
+
3. Step 3
|
|
46
|
+
|
|
47
|
+
## Expected Behavior
|
|
48
|
+
What should happen
|
|
49
|
+
|
|
50
|
+
## Actual Behavior
|
|
51
|
+
What actually happens
|
|
52
|
+
|
|
53
|
+
## Environment
|
|
54
|
+
- Browser/Runtime: [e.g., Chrome 90, Node.js 14]
|
|
55
|
+
- OS: [e.g., Windows 10, macOS, Ubuntu]
|
|
56
|
+
- Library Version: [e.g., 0.1.0]
|
|
57
|
+
|
|
58
|
+
## Code Example
|
|
59
|
+
\`\`\`javascript
|
|
60
|
+
// Minimal code to reproduce the issue
|
|
61
|
+
\`\`\`
|
|
62
|
+
|
|
63
|
+
## Screenshots
|
|
64
|
+
If applicable
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### I Have a Feature Request
|
|
68
|
+
|
|
69
|
+
**GitHub Issues**
|
|
70
|
+
1. Check [existing issues](https://github.com/oluokunkabiru/afro-locale/issues) for similar requests
|
|
71
|
+
2. [Create a new issue](https://github.com/oluokunkabiru/afro-locale/issues/new) with:
|
|
72
|
+
- Clear title
|
|
73
|
+
- Detailed description of the feature
|
|
74
|
+
- Use cases and benefits
|
|
75
|
+
- Possible implementation approach (optional)
|
|
76
|
+
|
|
77
|
+
**Feature Request Template:**
|
|
78
|
+
```markdown
|
|
79
|
+
## Feature Description
|
|
80
|
+
What would you like to add?
|
|
81
|
+
|
|
82
|
+
## Motivation
|
|
83
|
+
Why is this feature needed?
|
|
84
|
+
|
|
85
|
+
## Use Cases
|
|
86
|
+
- Use case 1
|
|
87
|
+
- Use case 2
|
|
88
|
+
|
|
89
|
+
## Possible Implementation
|
|
90
|
+
(Optional) How might this be implemented?
|
|
91
|
+
|
|
92
|
+
## Examples
|
|
93
|
+
Code examples showing how the feature would be used
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## 🐛 Common Issues & Solutions
|
|
97
|
+
|
|
98
|
+
### Issue: Locale not detecting browser language
|
|
99
|
+
|
|
100
|
+
**Solution:**
|
|
101
|
+
```javascript
|
|
102
|
+
import { locale } from '@koadit/afro-locale';
|
|
103
|
+
|
|
104
|
+
// Explicitly set the locale
|
|
105
|
+
locale.set('yo'); // Set to Yoruba
|
|
106
|
+
|
|
107
|
+
// Or detect and verify
|
|
108
|
+
const detected = locale.detectLocale();
|
|
109
|
+
console.log('Detected locale:', detected);
|
|
110
|
+
|
|
111
|
+
// Check if supported
|
|
112
|
+
if (locale.isLocaleSupported('yo')) {
|
|
113
|
+
locale.set('yo');
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Issue: Currency formatting shows unsupported currency error
|
|
118
|
+
|
|
119
|
+
**Solution:**
|
|
120
|
+
```javascript
|
|
121
|
+
import { locale } from '@koadit/afro-locale';
|
|
122
|
+
|
|
123
|
+
// Check if currency is supported
|
|
124
|
+
const supported = locale.getSupportedCurrencies();
|
|
125
|
+
console.log(supported); // See available currencies
|
|
126
|
+
|
|
127
|
+
// Use a supported currency
|
|
128
|
+
locale.formatCurrency(5000, 'NGN'); // ✓ Works
|
|
129
|
+
locale.formatCurrency(5000, 'XYZ'); // Shows "XYZ 5000.00"
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Issue: TypeScript errors with interfaces
|
|
133
|
+
|
|
134
|
+
**Solution:**
|
|
135
|
+
```typescript
|
|
136
|
+
import AfroLocale, { locale, LocaleConfig } from '@koadit/afro-locale';
|
|
137
|
+
|
|
138
|
+
// Make sure you're importing from the main index
|
|
139
|
+
// Not from individual files
|
|
140
|
+
|
|
141
|
+
const languages: LocaleConfig[] = locale.getSupportedLanguages();
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Issue: Build errors with ESM/CommonJS
|
|
145
|
+
|
|
146
|
+
**Solution:**
|
|
147
|
+
```javascript
|
|
148
|
+
// CommonJS
|
|
149
|
+
const { locale } = require('@koadit/afro-locale');
|
|
150
|
+
|
|
151
|
+
// ES Modules
|
|
152
|
+
import { locale } from '@koadit/afro-locale';
|
|
153
|
+
|
|
154
|
+
// TypeScript
|
|
155
|
+
import { locale } from '@koadit/afro-locale';
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Issue: Locale not persisting between page reloads
|
|
159
|
+
|
|
160
|
+
**Solution:**
|
|
161
|
+
```javascript
|
|
162
|
+
import { locale } from '@koadit/afro-locale';
|
|
163
|
+
|
|
164
|
+
// Save to localStorage
|
|
165
|
+
function setLocale(lang) {
|
|
166
|
+
locale.set(lang);
|
|
167
|
+
localStorage.setItem('preferredLocale', lang);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Load from localStorage
|
|
171
|
+
function loadLocale() {
|
|
172
|
+
const saved = localStorage.getItem('preferredLocale');
|
|
173
|
+
if (saved && locale.isLocaleSupported(saved)) {
|
|
174
|
+
locale.set(saved);
|
|
175
|
+
} else {
|
|
176
|
+
locale.detectLocale();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Initialize on page load
|
|
181
|
+
loadLocale();
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## 🚀 Performance Tips
|
|
185
|
+
|
|
186
|
+
### Reduce Formatting Calls
|
|
187
|
+
|
|
188
|
+
```javascript
|
|
189
|
+
// ❌ Inefficient - formats on every render
|
|
190
|
+
function Component() {
|
|
191
|
+
return <div>{locale.formatCurrency(price, 'NGN')}</div>;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// ✅ Better - memoize the result
|
|
195
|
+
const formattedPrice = useMemo(
|
|
196
|
+
() => locale.formatCurrency(price, 'NGN'),
|
|
197
|
+
[price]
|
|
198
|
+
);
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Cache Locale Instance Reference
|
|
202
|
+
|
|
203
|
+
```javascript
|
|
204
|
+
// ❌ Less efficient in loops
|
|
205
|
+
const amounts = [1000, 2000, 3000];
|
|
206
|
+
for (const amount of amounts) {
|
|
207
|
+
locale.set('yo');
|
|
208
|
+
console.log(locale.formatCurrency(amount, 'NGN'));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// ✅ Better
|
|
212
|
+
locale.set('yo');
|
|
213
|
+
for (const amount of amounts) {
|
|
214
|
+
console.log(locale.formatCurrency(amount, 'NGN'));
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## 📞 Contact & Social
|
|
219
|
+
|
|
220
|
+
- **Email Support**: support@koadit.com
|
|
221
|
+
- **Website**: [KOADIT Digital Solutions](https://koadit.com)
|
|
222
|
+
- **GitHub**: [afro-locale](https://github.com/oluokunkabiru/afro-locale)
|
|
223
|
+
- **NPM**: [@koadit/afro-locale](https://www.npmjs.com/package/@koadit/afro-locale)
|
|
224
|
+
|
|
225
|
+
## 💡 Tips for Faster Support
|
|
226
|
+
|
|
227
|
+
1. **Search First** - Check existing issues and discussions
|
|
228
|
+
2. **Minimal Examples** - Provide the smallest code that reproduces your issue
|
|
229
|
+
3. **Be Specific** - Clear, detailed descriptions help us help you faster
|
|
230
|
+
4. **Include Environment Info** - Browser/Node version, OS, library version
|
|
231
|
+
5. **Follow Up** - Update us on solutions that work for you
|
|
232
|
+
|
|
233
|
+
## 🎓 Learning Resources
|
|
234
|
+
|
|
235
|
+
### Documentation Files
|
|
236
|
+
- Getting started: [README.md](README.md)
|
|
237
|
+
- API reference: [API.md](API.md)
|
|
238
|
+
- Contributing guide: [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
239
|
+
|
|
240
|
+
### Code Examples
|
|
241
|
+
See `src/index.test.ts` for 28+ test examples showing how to use every feature
|
|
242
|
+
|
|
243
|
+
### Community
|
|
244
|
+
- [GitHub Discussions](https://github.com/oluokunkabiru/afro-locale/discussions)
|
|
245
|
+
- [GitHub Issues](https://github.com/oluokunkabiru/afro-locale/issues)
|
|
246
|
+
|
|
247
|
+
## 📋 Before Contacting Support
|
|
248
|
+
|
|
249
|
+
Please ensure:
|
|
250
|
+
- ✅ You've read the [README.md](README.md) and [API.md](API.md)
|
|
251
|
+
- ✅ You've checked [existing issues](https://github.com/oluokunkabiru/afro-locale/issues)
|
|
252
|
+
- ✅ You can provide a minimal reproduction case
|
|
253
|
+
- ✅ You're using a supported version of the library
|
|
254
|
+
|
|
255
|
+
## 🙏 Thank You
|
|
256
|
+
|
|
257
|
+
We appreciate your interest in `@koadit/afro-locale` and your patience with any issues.
|
|
258
|
+
|
|
259
|
+
Your feedback helps us make this library better for the entire African developer community!
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
**Last Updated:** April 2026
|
|
264
|
+
**Maintained by:** KOADIT Digital Solutions
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export interface CurrencyFormat {
|
|
2
|
+
symbol: string;
|
|
3
|
+
position: 'left' | 'right';
|
|
4
|
+
decimals: number;
|
|
5
|
+
}
|
|
6
|
+
export interface LocaleConfig {
|
|
7
|
+
code: string;
|
|
8
|
+
name: string;
|
|
9
|
+
nativeName: string;
|
|
10
|
+
country?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare class AfroLocale {
|
|
13
|
+
private currentLocale;
|
|
14
|
+
private languages;
|
|
15
|
+
private currencyFormats;
|
|
16
|
+
private localeMap;
|
|
17
|
+
set(locale: string): void;
|
|
18
|
+
get(): string;
|
|
19
|
+
/**
|
|
20
|
+
* Detect locale from browser navigator or system
|
|
21
|
+
*/
|
|
22
|
+
detectLocale(): string;
|
|
23
|
+
formatCurrency(amount: number, currency: string): string;
|
|
24
|
+
formatNumber(value: number, options?: Intl.NumberFormatOptions): string;
|
|
25
|
+
formatDate(date: Date, style?: 'short' | 'long'): string;
|
|
26
|
+
formatTime(date: Date, style?: 'short' | 'long'): string;
|
|
27
|
+
formatDateTime(date: Date, style?: 'short' | 'long'): string;
|
|
28
|
+
getLanguageName(code: string): string;
|
|
29
|
+
getLanguageNativeName(code: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Get all supported languages
|
|
32
|
+
*/
|
|
33
|
+
getSupportedLanguages(): LocaleConfig[];
|
|
34
|
+
/**
|
|
35
|
+
* Get all supported currencies
|
|
36
|
+
*/
|
|
37
|
+
getSupportedCurrencies(): string[];
|
|
38
|
+
/**
|
|
39
|
+
* Check if a locale is supported
|
|
40
|
+
*/
|
|
41
|
+
isLocaleSupported(locale: string): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Convert locale code to Intl format (e.g., 'yo' -> 'yo-NG')
|
|
44
|
+
*/
|
|
45
|
+
private getIntlLocale;
|
|
46
|
+
}
|
|
47
|
+
export declare const locale: AfroLocale;
|
|
48
|
+
export default AfroLocale;
|
|
49
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,aAAa,CAAgB;IAGrC,OAAO,CAAC,SAAS,CAuBf;IAEF,OAAO,CAAC,eAAe,CAerB;IAGF,OAAO,CAAC,SAAS,CAMf;IAEF,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAWzB,GAAG,IAAI,MAAM;IAIb;;OAEG;IACH,YAAY,IAAI,MAAM;IAWtB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAaxD,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,mBAAmB,GAAG,MAAM;IAKvE,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,GAAE,OAAO,GAAG,MAAe,GAAG,MAAM;IAQhE,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,GAAE,OAAO,GAAG,MAAgB,GAAG,MAAM;IAWjE,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,GAAE,OAAO,GAAG,MAAe,GAAG,MAAM;IAWpE,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAKrC,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAK3C;;OAEG;IACH,qBAAqB,IAAI,YAAY,EAAE;IAIvC;;OAEG;IACH,sBAAsB,IAAI,MAAM,EAAE;IAIlC;;OAEG;IACH,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAI1C;;OAEG;IACH,OAAO,CAAC,aAAa;CAOtB;AAED,eAAO,MAAM,MAAM,YAAmB,CAAC;AACvC,eAAe,UAAU,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.locale = exports.AfroLocale = void 0;
|
|
4
|
+
class AfroLocale {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.currentLocale = 'en';
|
|
7
|
+
// Comprehensive African languages support (20+)
|
|
8
|
+
this.languages = {
|
|
9
|
+
yo: { code: 'yo', name: 'Yoruba', nativeName: 'Yorùbá', country: 'NG' },
|
|
10
|
+
ha: { code: 'ha', name: 'Hausa', nativeName: 'Hausa', country: 'NG' },
|
|
11
|
+
ig: { code: 'ig', name: 'Igbo', nativeName: 'Igbo', country: 'NG' },
|
|
12
|
+
zu: { code: 'zu', name: 'Zulu', nativeName: 'isiZulu', country: 'ZA' },
|
|
13
|
+
sw: { code: 'sw', name: 'Swahili', nativeName: 'Kiswahili', country: 'KE' },
|
|
14
|
+
am: { code: 'am', name: 'Amharic', nativeName: 'አማርኛ', country: 'ET' },
|
|
15
|
+
so: { code: 'so', name: 'Somali', nativeName: 'Soomaali', country: 'SO' },
|
|
16
|
+
om: { code: 'om', name: 'Oromo', nativeName: 'Afaan Oromo', country: 'ET' },
|
|
17
|
+
ti: { code: 'ti', name: 'Tigrinya', nativeName: 'ትግርኛ', country: 'ER' },
|
|
18
|
+
rw: { code: 'rw', name: 'Kinyarwanda', nativeName: 'Kinyarwanda', country: 'RW' },
|
|
19
|
+
bn: { code: 'bn', name: 'Bambara', nativeName: 'Bamanankan', country: 'ML' },
|
|
20
|
+
ff: { code: 'ff', name: 'Fulfulde', nativeName: 'Fulfulde', country: 'SN' },
|
|
21
|
+
mg: { code: 'mg', name: 'Malagasy', nativeName: 'Malagasy', country: 'MG' },
|
|
22
|
+
xh: { code: 'xh', name: 'Xhosa', nativeName: 'isiXhosa', country: 'ZA' },
|
|
23
|
+
st: { code: 'st', name: 'Southern Sotho', nativeName: 'Sesotho', country: 'ZA' },
|
|
24
|
+
tn: { code: 'tn', name: 'Tswana', nativeName: 'Setswana', country: 'BW' },
|
|
25
|
+
sn: { code: 'sn', name: 'Shona', nativeName: 'Shona', country: 'ZW' },
|
|
26
|
+
ny: { code: 'ny', name: 'Chichewa', nativeName: 'Chichewa', country: 'MW' },
|
|
27
|
+
ln: { code: 'ln', name: 'Lingala', nativeName: 'Lingala', country: 'CD' },
|
|
28
|
+
ki: { code: 'ki', name: 'Kikuyu', nativeName: 'Gikuyu', country: 'KE' },
|
|
29
|
+
lu: { code: 'lu', name: 'Luba-Katanga', nativeName: 'Luba-Katanga', country: 'CD' },
|
|
30
|
+
en: { code: 'en', name: 'English', nativeName: 'English', country: 'GB' },
|
|
31
|
+
};
|
|
32
|
+
this.currencyFormats = {
|
|
33
|
+
NGN: { symbol: '₦', position: 'left', decimals: 2 },
|
|
34
|
+
GHS: { symbol: '₵', position: 'left', decimals: 2 },
|
|
35
|
+
KES: { symbol: 'KSh', position: 'left', decimals: 2 },
|
|
36
|
+
ZAR: { symbol: 'R', position: 'left', decimals: 2 },
|
|
37
|
+
ETB: { symbol: 'Br', position: 'left', decimals: 2 },
|
|
38
|
+
UGX: { symbol: 'USh', position: 'left', decimals: 0 },
|
|
39
|
+
TZS: { symbol: 'TSh', position: 'left', decimals: 2 },
|
|
40
|
+
RWF: { symbol: 'FRw', position: 'left', decimals: 0 },
|
|
41
|
+
MWK: { symbol: 'MK', position: 'left', decimals: 2 },
|
|
42
|
+
ZMW: { symbol: 'ZK', position: 'left', decimals: 2 },
|
|
43
|
+
XOF: { symbol: 'CFA', position: 'left', decimals: 0 }, // West African CFA
|
|
44
|
+
XAF: { symbol: 'FCFA', position: 'left', decimals: 0 }, // Central African CFA
|
|
45
|
+
USD: { symbol: '$', position: 'left', decimals: 2 },
|
|
46
|
+
EUR: { symbol: '€', position: 'right', decimals: 2 },
|
|
47
|
+
};
|
|
48
|
+
// Map to normalize locale codes
|
|
49
|
+
this.localeMap = {
|
|
50
|
+
'en-US': 'en',
|
|
51
|
+
'en-GB': 'en',
|
|
52
|
+
'en-ZA': 'zu',
|
|
53
|
+
'fr-SN': 'ff',
|
|
54
|
+
'pt-AO': 'ln',
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
set(locale) {
|
|
58
|
+
if (this.languages[locale]) {
|
|
59
|
+
this.currentLocale = locale;
|
|
60
|
+
}
|
|
61
|
+
else if (this.localeMap[locale]) {
|
|
62
|
+
this.currentLocale = this.localeMap[locale];
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
console.warn(`Locale "${locale}" not supported, defaulting to English`);
|
|
66
|
+
this.currentLocale = 'en';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
get() {
|
|
70
|
+
return this.currentLocale;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Detect locale from browser navigator or system
|
|
74
|
+
*/
|
|
75
|
+
detectLocale() {
|
|
76
|
+
if (typeof navigator !== 'undefined' && navigator.language) {
|
|
77
|
+
const lang = navigator.language.toLowerCase().split('-')[0];
|
|
78
|
+
if (this.languages[lang]) {
|
|
79
|
+
this.currentLocale = lang;
|
|
80
|
+
return lang;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return this.currentLocale;
|
|
84
|
+
}
|
|
85
|
+
formatCurrency(amount, currency) {
|
|
86
|
+
const format = this.currencyFormats[currency];
|
|
87
|
+
if (!format)
|
|
88
|
+
return `${currency} ${amount.toFixed(2)}`;
|
|
89
|
+
const formatter = new Intl.NumberFormat(this.getIntlLocale(), {
|
|
90
|
+
minimumFractionDigits: format.decimals,
|
|
91
|
+
maximumFractionDigits: format.decimals,
|
|
92
|
+
});
|
|
93
|
+
const formatted = formatter.format(amount);
|
|
94
|
+
return format.position === 'left' ? `${format.symbol}${formatted}` : `${formatted} ${format.symbol}`;
|
|
95
|
+
}
|
|
96
|
+
formatNumber(value, options) {
|
|
97
|
+
const formatter = new Intl.NumberFormat(this.getIntlLocale(), options);
|
|
98
|
+
return formatter.format(value);
|
|
99
|
+
}
|
|
100
|
+
formatDate(date, style = 'long') {
|
|
101
|
+
return new Intl.DateTimeFormat(this.getIntlLocale(), {
|
|
102
|
+
year: 'numeric',
|
|
103
|
+
month: style === 'long' ? 'long' : '2-digit',
|
|
104
|
+
day: '2-digit',
|
|
105
|
+
}).format(date);
|
|
106
|
+
}
|
|
107
|
+
formatTime(date, style = 'short') {
|
|
108
|
+
const options = {
|
|
109
|
+
hour: '2-digit',
|
|
110
|
+
minute: '2-digit',
|
|
111
|
+
};
|
|
112
|
+
if (style === 'long') {
|
|
113
|
+
options.second = '2-digit';
|
|
114
|
+
}
|
|
115
|
+
return new Intl.DateTimeFormat(this.getIntlLocale(), options).format(date);
|
|
116
|
+
}
|
|
117
|
+
formatDateTime(date, style = 'long') {
|
|
118
|
+
return new Intl.DateTimeFormat(this.getIntlLocale(), {
|
|
119
|
+
year: 'numeric',
|
|
120
|
+
month: style === 'long' ? 'long' : '2-digit',
|
|
121
|
+
day: '2-digit',
|
|
122
|
+
hour: '2-digit',
|
|
123
|
+
minute: '2-digit',
|
|
124
|
+
second: '2-digit',
|
|
125
|
+
}).format(date);
|
|
126
|
+
}
|
|
127
|
+
getLanguageName(code) {
|
|
128
|
+
const lang = this.languages[code];
|
|
129
|
+
return lang ? lang.name : code;
|
|
130
|
+
}
|
|
131
|
+
getLanguageNativeName(code) {
|
|
132
|
+
const lang = this.languages[code];
|
|
133
|
+
return lang ? lang.nativeName : code;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Get all supported languages
|
|
137
|
+
*/
|
|
138
|
+
getSupportedLanguages() {
|
|
139
|
+
return Object.values(this.languages);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Get all supported currencies
|
|
143
|
+
*/
|
|
144
|
+
getSupportedCurrencies() {
|
|
145
|
+
return Object.keys(this.currencyFormats);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Check if a locale is supported
|
|
149
|
+
*/
|
|
150
|
+
isLocaleSupported(locale) {
|
|
151
|
+
return locale in this.languages || locale in this.localeMap;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Convert locale code to Intl format (e.g., 'yo' -> 'yo-NG')
|
|
155
|
+
*/
|
|
156
|
+
getIntlLocale() {
|
|
157
|
+
const lang = this.languages[this.currentLocale];
|
|
158
|
+
if (lang && lang.country) {
|
|
159
|
+
return `${this.currentLocale}-${lang.country}`;
|
|
160
|
+
}
|
|
161
|
+
return this.currentLocale;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
exports.AfroLocale = AfroLocale;
|
|
165
|
+
exports.locale = new AfroLocale();
|
|
166
|
+
exports.default = AfroLocale;
|
|
167
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "afro-locale",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Internationalization library with first-class support for African languages and locales",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"require": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"README.md",
|
|
16
|
+
"CHANGELOG.md",
|
|
17
|
+
"CONTRIBUTING.md",
|
|
18
|
+
"SUPPORT.md",
|
|
19
|
+
"SECURITY.md",
|
|
20
|
+
"CODE_OF_CONDUCT.md",
|
|
21
|
+
"API.md",
|
|
22
|
+
"EXAMPLES.md",
|
|
23
|
+
"LICENSE"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc",
|
|
27
|
+
"test": "jest",
|
|
28
|
+
"test:coverage": "jest --coverage",
|
|
29
|
+
"lint": "eslint src --ext ts",
|
|
30
|
+
"type-check": "tsc --noEmit",
|
|
31
|
+
"prepack": "npm run build",
|
|
32
|
+
"prepare": "npm run build"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/jest": "^29.5.0",
|
|
36
|
+
"@types/node": "^20.0.0",
|
|
37
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
38
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
39
|
+
"eslint": "^9.0.0",
|
|
40
|
+
"jest": "^29.5.0",
|
|
41
|
+
"ts-jest": "^29.4.9",
|
|
42
|
+
"typescript": "^5.4.0"
|
|
43
|
+
},
|
|
44
|
+
"keywords": [
|
|
45
|
+
"i18n",
|
|
46
|
+
"localization",
|
|
47
|
+
"africa",
|
|
48
|
+
"languages",
|
|
49
|
+
"internationalization"
|
|
50
|
+
],
|
|
51
|
+
"author": "KOADIT Digital Solutions",
|
|
52
|
+
"license": "MIT",
|
|
53
|
+
"repository": {
|
|
54
|
+
"type": "git",
|
|
55
|
+
"url": "https://github.com/oluokunkabiru/afro-locale"
|
|
56
|
+
},
|
|
57
|
+
"bugs": {
|
|
58
|
+
"url": "https://github.com/oluokunkabiru/afro-locale/issues"
|
|
59
|
+
},
|
|
60
|
+
"homepage": "https://github.com/oluokunkabiru/afro-locale#readme"
|
|
61
|
+
}
|