millas 0.2.12-beta → 0.2.12-beta-2
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/package.json +3 -16
- package/src/admin/ActivityLog.js +153 -52
- package/src/admin/Admin.js +400 -167
- package/src/admin/AdminAuth.js +213 -98
- package/src/admin/FormGenerator.js +372 -0
- package/src/admin/HookRegistry.js +256 -0
- package/src/admin/QueryEngine.js +263 -0
- package/src/admin/ViewContext.js +309 -0
- package/src/admin/WidgetRegistry.js +406 -0
- package/src/admin/index.js +17 -0
- package/src/admin/resources/AdminResource.js +383 -97
- package/src/admin/static/admin.css +1341 -0
- package/src/admin/static/date-picker.css +157 -0
- package/src/admin/static/date-picker.js +316 -0
- package/src/admin/static/json-editor.css +649 -0
- package/src/admin/static/json-editor.js +1429 -0
- package/src/admin/static/ui.js +1044 -0
- package/src/admin/views/layouts/base.njk +65 -1013
- package/src/admin/views/pages/detail.njk +40 -16
- package/src/admin/views/pages/form.njk +47 -599
- package/src/admin/views/pages/list.njk +145 -62
- package/src/admin/views/partials/form-field.njk +53 -0
- package/src/admin/views/partials/form-footer.njk +28 -0
- package/src/admin/views/partials/form-readonly.njk +114 -0
- package/src/admin/views/partials/form-scripts.njk +476 -0
- package/src/admin/views/partials/form-widget.njk +296 -0
- package/src/admin/views/partials/json-dialog.njk +80 -0
- package/src/admin/views/partials/json-editor.njk +37 -0
- package/src/admin.zip +0 -0
- package/src/auth/Auth.js +31 -10
- package/src/auth/AuthController.js +3 -1
- package/src/auth/AuthUser.js +119 -0
- package/src/cli.js +4 -2
- package/src/commands/createsuperuser.js +254 -0
- package/src/commands/lang.js +589 -0
- package/src/commands/migrate.js +154 -81
- package/src/commands/serve.js +82 -110
- package/src/container/AppInitializer.js +215 -0
- package/src/container/Application.js +278 -253
- package/src/container/HttpServer.js +156 -0
- package/src/container/MillasApp.js +29 -279
- package/src/container/MillasConfig.js +192 -0
- package/src/core/admin.js +5 -0
- package/src/core/auth.js +9 -0
- package/src/core/db.js +9 -0
- package/src/core/foundation.js +59 -0
- package/src/core/http.js +11 -0
- package/src/core/lang.js +1 -0
- package/src/core/mail.js +6 -0
- package/src/core/queue.js +7 -0
- package/src/core/validation.js +29 -0
- package/src/facades/Admin.js +1 -1
- package/src/facades/Auth.js +22 -39
- package/src/facades/Cache.js +21 -10
- package/src/facades/Database.js +1 -1
- package/src/facades/Events.js +18 -17
- package/src/facades/Facade.js +197 -0
- package/src/facades/Http.js +42 -45
- package/src/facades/Log.js +25 -49
- package/src/facades/Mail.js +27 -32
- package/src/facades/Queue.js +22 -15
- package/src/facades/Storage.js +18 -10
- package/src/facades/Url.js +53 -0
- package/src/http/HttpClient.js +673 -0
- package/src/http/ResponseDispatcher.js +18 -111
- package/src/http/UrlGenerator.js +375 -0
- package/src/http/WelcomePage.js +273 -0
- package/src/http/adapters/ExpressAdapter.js +315 -0
- package/src/http/adapters/HttpAdapter.js +168 -0
- package/src/http/adapters/index.js +9 -0
- package/src/i18n/I18nServiceProvider.js +91 -0
- package/src/i18n/Translator.js +635 -0
- package/src/i18n/defaults.js +122 -0
- package/src/i18n/index.js +164 -0
- package/src/i18n/locales/en.js +55 -0
- package/src/i18n/locales/sw.js +48 -0
- package/src/index.js +5 -144
- package/src/logger/formatters/PrettyFormatter.js +103 -57
- package/src/logger/internal.js +2 -2
- package/src/logger/patchConsole.js +91 -81
- package/src/middleware/MiddlewareRegistry.js +62 -82
- package/src/migrations/system/0001_users.js +21 -0
- package/src/migrations/system/0002_admin_log.js +25 -0
- package/src/migrations/system/0003_sessions.js +23 -0
- package/src/orm/fields/index.js +210 -188
- package/src/orm/migration/DefaultValueParser.js +325 -0
- package/src/orm/migration/InteractiveResolver.js +191 -0
- package/src/orm/migration/Makemigrations.js +312 -0
- package/src/orm/migration/MigrationGraph.js +227 -0
- package/src/orm/migration/MigrationRunner.js +202 -108
- package/src/orm/migration/MigrationWriter.js +463 -0
- package/src/orm/migration/ModelInspector.js +412 -344
- package/src/orm/migration/ModelScanner.js +225 -0
- package/src/orm/migration/ProjectState.js +213 -0
- package/src/orm/migration/RenameDetector.js +175 -0
- package/src/orm/migration/SchemaBuilder.js +8 -81
- package/src/orm/migration/operations/base.js +57 -0
- package/src/orm/migration/operations/column.js +191 -0
- package/src/orm/migration/operations/fields.js +252 -0
- package/src/orm/migration/operations/index.js +55 -0
- package/src/orm/migration/operations/models.js +152 -0
- package/src/orm/migration/operations/registry.js +131 -0
- package/src/orm/migration/operations/special.js +51 -0
- package/src/orm/migration/utils.js +208 -0
- package/src/orm/model/Model.js +81 -13
- package/src/providers/AdminServiceProvider.js +66 -9
- package/src/providers/AuthServiceProvider.js +46 -7
- package/src/providers/CacheStorageServiceProvider.js +5 -3
- package/src/providers/DatabaseServiceProvider.js +3 -2
- package/src/providers/EventServiceProvider.js +2 -1
- package/src/providers/LogServiceProvider.js +7 -3
- package/src/providers/MailServiceProvider.js +4 -3
- package/src/providers/QueueServiceProvider.js +4 -3
- package/src/router/Router.js +119 -152
- package/src/scaffold/templates.js +83 -26
- package/src/facades/Validation.js +0 -69
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Millas framework default translatable strings.
|
|
5
|
+
*
|
|
6
|
+
* These are the strings used internally by Millas — validation messages,
|
|
7
|
+
* auth errors, admin panel labels, migration prompts, etc.
|
|
8
|
+
*
|
|
9
|
+
* When a developer runs `millas lang:publish sw --defaults`, these keys
|
|
10
|
+
* are merged into their locale file alongside their own app strings.
|
|
11
|
+
*
|
|
12
|
+
* Organised by module so translators know the context.
|
|
13
|
+
* All values are the English source text — same key = same value for 'en'.
|
|
14
|
+
*
|
|
15
|
+
* Format:
|
|
16
|
+
* 'key': 'English source text' — simple string
|
|
17
|
+
* 'key': ['singular', 'plural'] — plural form
|
|
18
|
+
* 'context|key': 'English source text' — contextual
|
|
19
|
+
*/
|
|
20
|
+
module.exports = {
|
|
21
|
+
|
|
22
|
+
// ── Validation ─────────────────────────────────────────────────────────
|
|
23
|
+
'This field is required.': 'This field is required.',
|
|
24
|
+
'Maximum {max} characters allowed.': 'Maximum {max} characters allowed.',
|
|
25
|
+
'Must be a whole number.': 'Must be a whole number.',
|
|
26
|
+
'Must be a number.': 'Must be a number.',
|
|
27
|
+
'Must be a valid email address.': 'Must be a valid email address.',
|
|
28
|
+
'Must be a valid URL.': 'Must be a valid URL.',
|
|
29
|
+
'Must be a valid date (YYYY-MM-DD).': 'Must be a valid date (YYYY-MM-DD).',
|
|
30
|
+
'Must be valid JSON.': 'Must be valid JSON.',
|
|
31
|
+
'Must be a valid UUID.': 'Must be a valid UUID.',
|
|
32
|
+
'Please select a value.': 'Please select a value.',
|
|
33
|
+
'Please select a related record.': 'Please select a related record.',
|
|
34
|
+
'Invalid value. Must be one of: {values}': 'Invalid value. Must be one of: {values}',
|
|
35
|
+
'Password must be at least 8 characters.': 'Password must be at least 8 characters.',
|
|
36
|
+
|
|
37
|
+
// ── Auth ───────────────────────────────────────────────────────────────
|
|
38
|
+
'Email is required': 'Email is required',
|
|
39
|
+
'Password is required': 'Password is required',
|
|
40
|
+
'Invalid email or password': 'Invalid email or password',
|
|
41
|
+
'Your account has been deactivated': 'Your account has been deactivated',
|
|
42
|
+
'Email already in use': 'Email already in use',
|
|
43
|
+
'Passwords do not match': 'Passwords do not match',
|
|
44
|
+
'Token has expired': 'Token has expired',
|
|
45
|
+
'Invalid token': 'Invalid token',
|
|
46
|
+
'You are not authorized to perform this action': 'You are not authorized to perform this action',
|
|
47
|
+
|
|
48
|
+
// ── HTTP errors ────────────────────────────────────────────────────────
|
|
49
|
+
'Not Found': 'Not Found',
|
|
50
|
+
'Unauthorized': 'Unauthorized',
|
|
51
|
+
'Forbidden': 'Forbidden',
|
|
52
|
+
'Unprocessable Entity': 'Unprocessable Entity',
|
|
53
|
+
'Internal Server Error': 'Internal Server Error',
|
|
54
|
+
'Too Many Requests': 'Too Many Requests',
|
|
55
|
+
'{model} #{id} not found': '{model} #{id} not found',
|
|
56
|
+
|
|
57
|
+
// ── Pagination ─────────────────────────────────────────────────────────
|
|
58
|
+
'Showing {from} to {to} of {total} results': 'Showing {from} to {to} of {total} results',
|
|
59
|
+
'Previous': 'Previous',
|
|
60
|
+
'Next': 'Next',
|
|
61
|
+
'Page {page} of {total}': 'Page {page} of {total}',
|
|
62
|
+
|
|
63
|
+
// ── CRUD ───────────────────────────────────────────────────────────────
|
|
64
|
+
'{model} created successfully': '{model} created successfully',
|
|
65
|
+
'{model} updated successfully': '{model} updated successfully',
|
|
66
|
+
'{model} deleted': '{model} deleted',
|
|
67
|
+
'No records found': 'No records found',
|
|
68
|
+
'Record not found': 'Record not found',
|
|
69
|
+
|
|
70
|
+
// ── Plural CRUD ────────────────────────────────────────────────────────
|
|
71
|
+
'{count} record deleted': ['{count} record deleted', '{count} records deleted'],
|
|
72
|
+
'{count} record updated': ['{count} record updated', '{count} records updated'],
|
|
73
|
+
|
|
74
|
+
// ── Admin panel ────────────────────────────────────────────────────────
|
|
75
|
+
'Dashboard': 'Dashboard',
|
|
76
|
+
'Search': 'Search',
|
|
77
|
+
'Filters': 'Filters',
|
|
78
|
+
'Actions': 'Actions',
|
|
79
|
+
'Export CSV': 'Export CSV',
|
|
80
|
+
'Export JSON': 'Export JSON',
|
|
81
|
+
'Save': 'Save',
|
|
82
|
+
'Save and continue editing': 'Save and continue editing',
|
|
83
|
+
'Save and add another': 'Save and add another',
|
|
84
|
+
'Delete': 'Delete',
|
|
85
|
+
'Cancel': 'Cancel',
|
|
86
|
+
'Edit': 'Edit',
|
|
87
|
+
'Add {model}': 'Add {model}',
|
|
88
|
+
'Change {model}': 'Change {model}',
|
|
89
|
+
'Delete {model}': 'Delete {model}',
|
|
90
|
+
'Are you sure you want to delete {label}?': 'Are you sure you want to delete {label}?',
|
|
91
|
+
'This action cannot be undone.': 'This action cannot be undone.',
|
|
92
|
+
'No {model} yet': 'No {model} yet',
|
|
93
|
+
'Select all': 'Select all',
|
|
94
|
+
'Deselect all': 'Deselect all',
|
|
95
|
+
|
|
96
|
+
// ── Admin status badges (contextual) ───────────────────────────────────
|
|
97
|
+
'status|active': 'Active',
|
|
98
|
+
'status|inactive': 'Inactive',
|
|
99
|
+
'status|pending': 'Pending',
|
|
100
|
+
'status|approved': 'Approved',
|
|
101
|
+
'status|rejected': 'Rejected',
|
|
102
|
+
'status|draft': 'Draft',
|
|
103
|
+
'status|published': 'Published',
|
|
104
|
+
|
|
105
|
+
// ── Admin login ────────────────────────────────────────────────────────
|
|
106
|
+
'Sign in to your account': 'Sign in to your account',
|
|
107
|
+
'Email address': 'Email address',
|
|
108
|
+
'Password': 'Password',
|
|
109
|
+
'Remember me': 'Remember me',
|
|
110
|
+
'Sign in': 'Sign in',
|
|
111
|
+
'Sign out': 'Sign out',
|
|
112
|
+
'You have been logged out.': 'You have been logged out.',
|
|
113
|
+
|
|
114
|
+
// ── Migration prompts ──────────────────────────────────────────────────
|
|
115
|
+
'No changes detected.': 'No changes detected.',
|
|
116
|
+
'Migrations generated:': 'Migrations generated:',
|
|
117
|
+
'Run: millas migrate to apply.': 'Run: millas migrate to apply.',
|
|
118
|
+
|
|
119
|
+
// ── Queue ──────────────────────────────────────────────────────────────
|
|
120
|
+
'Job failed: {message}': 'Job failed: {message}',
|
|
121
|
+
'Job completed: {job}': 'Job completed: {job}',
|
|
122
|
+
};
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Translator = require('./Translator');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Trans — global translation singleton + shorthand helpers.
|
|
7
|
+
*
|
|
8
|
+
* This is the object you import in controllers, models, views, and commands.
|
|
9
|
+
* It wraps the Translator instance with the Django-style shorthand functions.
|
|
10
|
+
*
|
|
11
|
+
* ── Import styles ──────────────────────────────────────────────────────────
|
|
12
|
+
*
|
|
13
|
+
* // Named destructuring (recommended)
|
|
14
|
+
* const { __, _n, _p, _f } = require('millas/src/i18n');
|
|
15
|
+
*
|
|
16
|
+
* // Full facade for locale control
|
|
17
|
+
* const { Trans } = require('millas/src/i18n');
|
|
18
|
+
* Trans.setLocale('sw');
|
|
19
|
+
*
|
|
20
|
+
* ── API ────────────────────────────────────────────────────────────────────
|
|
21
|
+
*
|
|
22
|
+
* __('Hello')
|
|
23
|
+
* → 'Habari' (when locale=sw)
|
|
24
|
+
* → 'Hello' (when locale=en or no translation found)
|
|
25
|
+
*
|
|
26
|
+
* _n('You have %d message', 'You have %d messages', 3)
|
|
27
|
+
* → 'Una ujumbe 3'
|
|
28
|
+
*
|
|
29
|
+
* _p('menu', 'File')
|
|
30
|
+
* → 'Faili' (contextual — same word, different contexts)
|
|
31
|
+
*
|
|
32
|
+
* _f('Welcome, {name}!', { name: 'Alice' })
|
|
33
|
+
* → 'Karibu, Alice!'
|
|
34
|
+
*
|
|
35
|
+
* _f('Hello %s, you have %d items', 'Alice', 5)
|
|
36
|
+
* → 'Habari Alice, una vitu 5'
|
|
37
|
+
*
|
|
38
|
+
* _fn('You have %d item', 'You have %d items', 3)
|
|
39
|
+
* → 'Una vitu 3'
|
|
40
|
+
*
|
|
41
|
+
* ── In templates (Nunjucks) ────────────────────────────────────────────────
|
|
42
|
+
*
|
|
43
|
+
* Add the filters via I18nServiceProvider (done automatically):
|
|
44
|
+
*
|
|
45
|
+
* {{ 'Hello' | __ }}
|
|
46
|
+
* {{ 'You have %d messages' | _n(count) }}
|
|
47
|
+
* {{ 'Welcome, {name}!' | _f({ name: user.name }) }}
|
|
48
|
+
*
|
|
49
|
+
* ── In CLI commands ────────────────────────────────────────────────────────
|
|
50
|
+
*
|
|
51
|
+
* const { __ } = require('millas/src/i18n');
|
|
52
|
+
* console.log(__('Migrations applied successfully.'));
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
// ── Singleton Translator instance ────────────────────────────────────────────
|
|
56
|
+
const Trans = new Translator();
|
|
57
|
+
|
|
58
|
+
// ── Shorthand functions ───────────────────────────────────────────────────────
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* gettext — translate a string.
|
|
62
|
+
*
|
|
63
|
+
* __('Hello')
|
|
64
|
+
* __('Hello', 'sw') // explicit locale override
|
|
65
|
+
*
|
|
66
|
+
* @param {string} key
|
|
67
|
+
* @param {string} [locale]
|
|
68
|
+
* @returns {string}
|
|
69
|
+
*/
|
|
70
|
+
function __(key, locale) {
|
|
71
|
+
return Trans.translate(key, locale);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* ngettext — singular/plural translation.
|
|
76
|
+
*
|
|
77
|
+
* _n('You have %d message', 'You have %d messages', count)
|
|
78
|
+
*
|
|
79
|
+
* Note: this does NOT interpolate %d — call _fn() if you also need
|
|
80
|
+
* the count substituted into the string.
|
|
81
|
+
*
|
|
82
|
+
* @param {string} singular
|
|
83
|
+
* @param {string} plural
|
|
84
|
+
* @param {number} count
|
|
85
|
+
* @param {string} [locale]
|
|
86
|
+
* @returns {string}
|
|
87
|
+
*/
|
|
88
|
+
function _n(singular, plural, count, locale) {
|
|
89
|
+
return Trans.ngettext(singular, plural, count, locale);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* pgettext — contextual translation.
|
|
94
|
+
*
|
|
95
|
+
* _p('menu', 'File') // the menu item "File"
|
|
96
|
+
* _p('action', 'File') // the action "to file something"
|
|
97
|
+
*
|
|
98
|
+
* @param {string} context
|
|
99
|
+
* @param {string} key
|
|
100
|
+
* @param {string} [locale]
|
|
101
|
+
* @returns {string}
|
|
102
|
+
*/
|
|
103
|
+
function _p(context, key, locale) {
|
|
104
|
+
return Trans.pgettext(context, key, locale);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* format — translate + interpolate named or positional variables.
|
|
109
|
+
*
|
|
110
|
+
* _f('Welcome, {name}!', { name: 'Alice' })
|
|
111
|
+
* _f('Hello %s, you have %d items', 'Alice', 5)
|
|
112
|
+
*
|
|
113
|
+
* @param {string} key
|
|
114
|
+
* @param {...*} args
|
|
115
|
+
* @returns {string}
|
|
116
|
+
*/
|
|
117
|
+
function _f(key, ...args) {
|
|
118
|
+
return Trans.format(key, ...args);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* nformat — plural translation + interpolation.
|
|
123
|
+
*
|
|
124
|
+
* _fn('You have %d item', 'You have %d items', count)
|
|
125
|
+
* // → 'You have 3 items' (count is auto-interpolated as first %d)
|
|
126
|
+
*
|
|
127
|
+
* @param {string} singular
|
|
128
|
+
* @param {string} plural
|
|
129
|
+
* @param {number} count
|
|
130
|
+
* @param {...*} args — additional interpolation values after count
|
|
131
|
+
* @returns {string}
|
|
132
|
+
*/
|
|
133
|
+
function _fn(singular, plural, count, ...args) {
|
|
134
|
+
return Trans.nformat(singular, plural, count, ...args);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* lazy — returns a lazy-evaluated translation proxy.
|
|
139
|
+
*
|
|
140
|
+
* Useful when the translation needs to be stored before the locale is set
|
|
141
|
+
* (e.g. in class-level constants, model field labels).
|
|
142
|
+
*
|
|
143
|
+
* const label = lazy__('Email address');
|
|
144
|
+
* // label() → 'Anwani ya barua pepe' (evaluated at call time)
|
|
145
|
+
*
|
|
146
|
+
* @param {string} key
|
|
147
|
+
* @returns {Function}
|
|
148
|
+
*/
|
|
149
|
+
function lazy__(key) {
|
|
150
|
+
return () => Trans.translate(key);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
module.exports = {
|
|
154
|
+
// Singleton for locale control + advanced usage
|
|
155
|
+
Trans,
|
|
156
|
+
|
|
157
|
+
// Shorthand functions
|
|
158
|
+
__,
|
|
159
|
+
_n,
|
|
160
|
+
_p,
|
|
161
|
+
_f,
|
|
162
|
+
_fn,
|
|
163
|
+
lazy__,
|
|
164
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* English (en) — source language catalogue.
|
|
5
|
+
*
|
|
6
|
+
* For the source language this file acts as documentation:
|
|
7
|
+
* it lists every translatable string in the application.
|
|
8
|
+
* Values are the same as keys — no actual translation needed.
|
|
9
|
+
*
|
|
10
|
+
* Other locale files only need to include keys where the translation
|
|
11
|
+
* differs. Missing keys fall back to this file, then to the raw key.
|
|
12
|
+
*
|
|
13
|
+
* ── Auth ──────────────────────────────────────────────────────────────────
|
|
14
|
+
*/
|
|
15
|
+
module.exports = {
|
|
16
|
+
|
|
17
|
+
// ── Auth / validation ────────────────────────────────────────────────────
|
|
18
|
+
'Email is required': 'Email is required',
|
|
19
|
+
'Password is required': 'Password is required',
|
|
20
|
+
'Invalid email or password': 'Invalid email or password',
|
|
21
|
+
'Your account has been deactivated': 'Your account has been deactivated',
|
|
22
|
+
'Email already in use': 'Email already in use',
|
|
23
|
+
'Password must be at least 8 characters': 'Password must be at least 8 characters',
|
|
24
|
+
'Passwords do not match': 'Passwords do not match',
|
|
25
|
+
|
|
26
|
+
// ── CRUD messages ────────────────────────────────────────────────────────
|
|
27
|
+
'%s created successfully': '%s created successfully',
|
|
28
|
+
'%s updated successfully': '%s updated successfully',
|
|
29
|
+
'%s deleted': '%s deleted',
|
|
30
|
+
'No records found': 'No records found',
|
|
31
|
+
'Record not found': 'Record not found',
|
|
32
|
+
|
|
33
|
+
// ── Pagination ───────────────────────────────────────────────────────────
|
|
34
|
+
'Showing %d to %d of %d results': 'Showing %d to %d of %d results',
|
|
35
|
+
'Previous': 'Previous',
|
|
36
|
+
'Next': 'Next',
|
|
37
|
+
|
|
38
|
+
// ── Plural examples ──────────────────────────────────────────────────────
|
|
39
|
+
// Array format: [singular_form, plural_form, ...]
|
|
40
|
+
'You have %d message': ['You have %d message', 'You have %d messages'],
|
|
41
|
+
'%d item selected': ['%d item selected', '%d items selected'],
|
|
42
|
+
'%d record deleted': ['%d record deleted', '%d records deleted'],
|
|
43
|
+
|
|
44
|
+
// ── Contextual examples (context|key) ────────────────────────────────────
|
|
45
|
+
'menu|File': 'File',
|
|
46
|
+
'menu|Edit': 'Edit',
|
|
47
|
+
'status|active': 'Active',
|
|
48
|
+
'status|inactive': 'Inactive',
|
|
49
|
+
'status|pending': 'Pending',
|
|
50
|
+
|
|
51
|
+
// ── Named interpolation examples ─────────────────────────────────────────
|
|
52
|
+
'Welcome, {name}!': 'Welcome, {name}!',
|
|
53
|
+
'Hello, {name}. You have {count} notifications.':
|
|
54
|
+
'Hello, {name}. You have {count} notifications.',
|
|
55
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Swahili (sw) translation catalogue.
|
|
5
|
+
*
|
|
6
|
+
* Only include keys where the translation differs from the source.
|
|
7
|
+
* Missing keys automatically fall back to the fallback locale (en).
|
|
8
|
+
*/
|
|
9
|
+
module.exports = {
|
|
10
|
+
|
|
11
|
+
// ── Auth / validation ────────────────────────────────────────────────────
|
|
12
|
+
'Email is required': 'Barua pepe inahitajika',
|
|
13
|
+
'Password is required': 'Nywila inahitajika',
|
|
14
|
+
'Invalid email or password': 'Barua pepe au nywila si sahihi',
|
|
15
|
+
'Your account has been deactivated': 'Akaunti yako imezimwa',
|
|
16
|
+
'Email already in use': 'Barua pepe hiyo tayari inatumika',
|
|
17
|
+
'Password must be at least 8 characters': 'Nywila lazima iwe na herufi angalau 8',
|
|
18
|
+
'Passwords do not match': 'Nywila hazifanani',
|
|
19
|
+
|
|
20
|
+
// ── CRUD messages ────────────────────────────────────────────────────────
|
|
21
|
+
'%s created successfully': '%s imeundwa kikamilifu',
|
|
22
|
+
'%s updated successfully': '%s imesasishwa kikamilifu',
|
|
23
|
+
'%s deleted': '%s imefutwa',
|
|
24
|
+
'No records found': 'Hakuna rekodi zilizopatikana',
|
|
25
|
+
'Record not found': 'Rekodi haijapatikana',
|
|
26
|
+
|
|
27
|
+
// ── Pagination ───────────────────────────────────────────────────────────
|
|
28
|
+
'Showing %d to %d of %d results': 'Inaonyesha %d hadi %d kati ya %d matokeo',
|
|
29
|
+
'Previous': 'Iliyotangulia',
|
|
30
|
+
'Next': 'Inayofuata',
|
|
31
|
+
|
|
32
|
+
// ── Plural forms (Swahili uses same form for all counts) ─────────────────
|
|
33
|
+
'You have %d message': ['Una ujumbe %d', 'Una ujumbe %d'],
|
|
34
|
+
'%d item selected': ['%d kipengele kimechaguliwa', '%d vipengele vimechaguliwa'],
|
|
35
|
+
'%d record deleted': ['Rekodi %d imefutwa', 'Rekodi %d zimefutwa'],
|
|
36
|
+
|
|
37
|
+
// ── Contextual ───────────────────────────────────────────────────────────
|
|
38
|
+
'menu|File': 'Faili',
|
|
39
|
+
'menu|Edit': 'Hariri',
|
|
40
|
+
'status|active': 'Amilifu',
|
|
41
|
+
'status|inactive':'Haifanyi kazi',
|
|
42
|
+
'status|pending': 'Inasubiri',
|
|
43
|
+
|
|
44
|
+
// ── Named interpolation ──────────────────────────────────────────────────
|
|
45
|
+
'Welcome, {name}!': 'Karibu, {name}!',
|
|
46
|
+
'Hello, {name}. You have {count} notifications.':
|
|
47
|
+
'Habari {name}. Una arifa {count}.',
|
|
48
|
+
};
|
package/src/index.js
CHANGED
|
@@ -1,147 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
const {
|
|
5
|
-
MillasRequest,
|
|
6
|
-
MillasResponse,
|
|
7
|
-
ResponseDispatcher,
|
|
8
|
-
jsonify,
|
|
9
|
-
view,
|
|
10
|
-
redirect,
|
|
11
|
-
text,
|
|
12
|
-
file,
|
|
13
|
-
empty,
|
|
14
|
-
abort,
|
|
15
|
-
notFound,
|
|
16
|
-
unauthorized,
|
|
17
|
-
forbidden,
|
|
18
|
-
} = require('./http/index');
|
|
19
|
-
const RequestContext = require('./http/RequestContext');
|
|
3
|
+
const Millas = require('./container/MillasApp');
|
|
20
4
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
StringValidator,
|
|
26
|
-
EmailValidator,
|
|
27
|
-
NumberValidator,
|
|
28
|
-
BooleanValidator,
|
|
29
|
-
DateValidator,
|
|
30
|
-
ArrayValidator,
|
|
31
|
-
ObjectValidator,
|
|
32
|
-
FileValidator,
|
|
33
|
-
string,
|
|
34
|
-
email,
|
|
35
|
-
number,
|
|
36
|
-
boolean,
|
|
37
|
-
date,
|
|
38
|
-
array,
|
|
39
|
-
object: objectField,
|
|
40
|
-
file: fileField,
|
|
41
|
-
} = require('./validation/Validator');
|
|
42
|
-
const MillasApp = require('./container/MillasApp');
|
|
43
|
-
// ── HTTP Layer (old) ──────────────────────────────────────────────
|
|
44
|
-
const Controller = require('./controller/Controller');
|
|
45
|
-
const Middleware = require('./middleware/Middleware');
|
|
46
|
-
const MiddlewarePipeline = require('./middleware/MiddlewarePipeline');
|
|
47
|
-
const CorsMiddleware = require('./middleware/CorsMiddleware');
|
|
48
|
-
const ThrottleMiddleware = require('./middleware/ThrottleMiddleware');
|
|
49
|
-
const LogMiddleware = require('./middleware/LogMiddleware');
|
|
50
|
-
const HttpError = require('./errors/HttpError');
|
|
51
|
-
|
|
52
|
-
// ── DI Container ─────────────────────────────────────────────────
|
|
53
|
-
const Container = require('./container/Container');
|
|
54
|
-
const Application = require('./container/Application');
|
|
55
|
-
const ServiceProvider = require('./providers/ServiceProvider');
|
|
56
|
-
const ProviderRegistry = require('./providers/ProviderRegistry');
|
|
57
|
-
|
|
58
|
-
// ── ORM ───────────────────────────────────────────────────────────
|
|
59
|
-
const { Model, fields, QueryBuilder, DatabaseManager,
|
|
60
|
-
SchemaBuilder, MigrationRunner, ModelInspector } = require('./orm');
|
|
61
|
-
const DatabaseServiceProvider = require('./providers/DatabaseServiceProvider');
|
|
62
|
-
|
|
63
|
-
// ── Auth ──────────────────────────────────────────────────────────
|
|
64
|
-
const Auth = require('./auth/Auth');
|
|
65
|
-
const Hasher = require('./auth/Hasher');
|
|
66
|
-
const JwtDriver = require('./auth/JwtDriver');
|
|
67
|
-
const AuthMiddleware = require('./auth/AuthMiddleware');
|
|
68
|
-
const RoleMiddleware = require('./auth/RoleMiddleware');
|
|
69
|
-
const AuthController = require('./auth/AuthController');
|
|
70
|
-
const AuthServiceProvider = require('./providers/AuthServiceProvider');
|
|
71
|
-
|
|
72
|
-
// ── Mail ──────────────────────────────────────────────────────────
|
|
73
|
-
const { Mail, MailMessage, TemplateEngine,
|
|
74
|
-
SmtpDriver, SendGridDriver, MailgunDriver, LogDriver } = require('./mail');
|
|
75
|
-
const MailServiceProvider = require('./providers/MailServiceProvider');
|
|
76
|
-
|
|
77
|
-
// ── Queue ─────────────────────────────────────────────────────────
|
|
78
|
-
const Queue = require('./queue/Queue');
|
|
79
|
-
const Job = require('./queue/Job');
|
|
80
|
-
const QueueWorker = require('./queue/workers/QueueWorker');
|
|
81
|
-
const { dispatch } = require('./queue/Queue');
|
|
82
|
-
const QueueServiceProvider = require('./providers/QueueServiceProvider');
|
|
83
|
-
|
|
84
|
-
// ── Events ────────────────────────────────────────────────────────
|
|
85
|
-
const EventEmitter = require('./events/EventEmitter');
|
|
86
|
-
const Event = require('./events/Event');
|
|
87
|
-
const Listener = require('./events/Listener');
|
|
88
|
-
const { emit } = require('./events/EventEmitter');
|
|
89
|
-
const EventServiceProvider = require('./providers/EventServiceProvider');
|
|
90
|
-
|
|
91
|
-
// ── Cache ─────────────────────────────────────────────────────────
|
|
92
|
-
const Cache = require('./cache/Cache');
|
|
93
|
-
const MemoryDriver = require('./cache/drivers/MemoryDriver');
|
|
94
|
-
const FileDriver = require('./cache/drivers/FileDriver');
|
|
95
|
-
const NullDriver = require('./cache/drivers/NullDriver');
|
|
96
|
-
const { CacheServiceProvider, StorageServiceProvider } = require('./providers/CacheStorageServiceProvider');
|
|
97
|
-
|
|
98
|
-
// ── Storage ───────────────────────────────────────────────────────
|
|
99
|
-
const Storage = require('./storage/Storage');
|
|
100
|
-
const LocalDriver = require('./storage/drivers/LocalDriver');
|
|
101
|
-
|
|
102
|
-
module.exports = {
|
|
103
|
-
// Millas App
|
|
104
|
-
MillasApp,
|
|
105
|
-
// ── Millas HTTP layer ──────────────────────────────────────────
|
|
106
|
-
MillasRequest, MillasResponse, ResponseDispatcher, RequestContext,
|
|
107
|
-
jsonify, view, redirect, text, send_file:file, empty,
|
|
108
|
-
abort, notFound, unauthorized, forbidden,
|
|
109
|
-
// ── Validation ────────────────────────────────────────────────
|
|
110
|
-
Validator,
|
|
111
|
-
BaseValidator,
|
|
112
|
-
StringValidator, EmailValidator, NumberValidator, BooleanValidator,
|
|
113
|
-
DateValidator, ArrayValidator, ObjectValidator, FileValidator,
|
|
114
|
-
string, email, number, boolean, date, array,
|
|
115
|
-
object: objectField,
|
|
116
|
-
file: fileField,
|
|
117
|
-
// HTTP
|
|
118
|
-
Controller, Middleware, MiddlewarePipeline,
|
|
119
|
-
CorsMiddleware, ThrottleMiddleware, LogMiddleware, HttpError,
|
|
120
|
-
// DI
|
|
121
|
-
Container, Application, ServiceProvider, ProviderRegistry,
|
|
122
|
-
// ORM
|
|
123
|
-
Model, fields, QueryBuilder, DatabaseManager, SchemaBuilder,
|
|
124
|
-
MigrationRunner, ModelInspector, DatabaseServiceProvider,
|
|
125
|
-
// Auth
|
|
126
|
-
Auth, Hasher, JwtDriver, AuthMiddleware, RoleMiddleware,
|
|
127
|
-
AuthController, AuthServiceProvider,
|
|
128
|
-
// Mail
|
|
129
|
-
Mail, MailMessage, TemplateEngine,
|
|
130
|
-
SmtpDriver, SendGridDriver, MailgunDriver, LogDriver, MailServiceProvider,
|
|
131
|
-
// Queue
|
|
132
|
-
Queue, Job, QueueWorker, dispatch, QueueServiceProvider,
|
|
133
|
-
// Events
|
|
134
|
-
EventEmitter, Event, Listener, emit, EventServiceProvider,
|
|
135
|
-
// Cache
|
|
136
|
-
Cache, MemoryDriver, FileDriver, NullDriver, CacheServiceProvider,
|
|
137
|
-
// Storage
|
|
138
|
-
Storage, LocalDriver, StorageServiceProvider,
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
// ── Admin ─────────────────────────────────────────────────────────
|
|
142
|
-
const { Admin, AdminResource, AdminField, AdminFilter } = require('./admin');
|
|
143
|
-
const AdminServiceProvider = require('./providers/AdminServiceProvider');
|
|
144
|
-
|
|
145
|
-
Object.assign(module.exports, {
|
|
146
|
-
Admin, AdminResource, AdminField, AdminFilter, AdminServiceProvider,
|
|
147
|
-
});
|
|
5
|
+
/**
|
|
6
|
+
* @module millas
|
|
7
|
+
*/
|
|
8
|
+
module.exports = { Millas };
|