imba-localization 0.1.4 β†’ 0.1.6

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/README.md CHANGED
@@ -1,90 +1,270 @@
1
1
 
2
- # JSON Localization for Imba
2
+ # 🌐 JSON Localization for Imba
3
3
 
4
- A lightweight Imba module for loading and handling JSON-based localization files in web applications. This utility fetches a localization file, selects the appropriate language based on the user's browser settings (or falls back to a default), and allows you to easily access localized strings throughout your application.
4
+ A lightweight Imba module for loading and handling JSON-based localization files in web applications. This utility fetches a localization file, selects the appropriate language based on the user's browser settings (or falls back to a default), and allows you to easily access localized strings throughout your application. Package includes helpful components for language selection and localization management.
5
5
 
6
6
  ## ✨ Features
7
7
 
8
- - Automatically detects the user's preferred language
9
- - Falls back to a default language if needed
10
- - Proxy-based access to translation strings
11
- - Supports `onready`, `onchange` and `onerror` events
12
- - Simple to use in any Imba-based web application
8
+ - πŸ” **Automatic language detection** - Uses the user's browser language settings
9
+ - πŸ”„ **Smart fallback system** - Falls back to a default language when needed
10
+ - 🧠 **Intuitive access** - Proxy-based access to translation strings
11
+ - πŸ“‘ **Event handling** - Support for `onready`, `onchange`, and `onerror` events
12
+ - πŸš€ **Simple integration** - Easy to use in any Imba-based web application
13
+ - 🧩 **<LanguageSelector>** - Plug and play component for switching languages
14
+
15
+ ## πŸ“˜ Notes
16
+
17
+ - Language detection uses the first two characters from `navigator.language` (e.g., `en` from `en-US`)
18
+ - If the preferred language isn't available in your JSON file, it falls back to the default language
19
+ - Returns an empty string for missing translation keys instead of throwing errors
20
+
13
21
 
14
22
  ## πŸ“¦ Installation
15
23
 
16
- Just include the module in your project or copy the class directly into your codebase.
17
24
  ```bash
25
+ # NodeJs
18
26
  npm install imba-localization
27
+ # or Bun
28
+ bun add imba-localization
19
29
  ```
20
30
 
21
- ## πŸš€ Usage
31
+ ## πŸš€ Quick Start
32
+
33
+ ### 1️⃣ Preload the localization file
34
+
35
+ Add this to your HTML head to load the localization file simultaneously with your application:
22
36
 
23
- First of all, preload the localization file in HTML head, so it is loaded simultaniously with the application itself:
24
37
  ```html
25
38
  <!DOCTYPE html>
26
39
  <html lang="en">
27
- <head>
28
- ...
29
- <link rel="preload" href="ADDRESS_TO_JSON" as="fetch" type="application/json" crossorigin="anonymous"/>
30
- ...
31
- </head>
32
- <body>
33
- </body>
40
+ <head>
41
+ <!-- Other head elements -->
42
+ <link rel="preload" href="path/to/lang.json" as="fetch" type="application/json" crossorigin="anonymous"/>
43
+ </head>
44
+ <body>
45
+ <!-- Your app -->
46
+ </body>
34
47
  </html>
35
48
  ```
36
- Such localization file can be placed on any static hosting. In my experience Github Pages works perfectly for that purpose. Moreover, it also allows to update localization by just pushing updated file to the repository.
37
49
 
38
- Here’s an example of how to use it in an Imba app:
50
+ > πŸ’‘ **Tip:** You can host your localization file on GitHub Pages or any static hosting service, making it easy to update translations without redeploying your application.
51
+
52
+ ### 2️⃣ Initialize in your Imba app
39
53
 
40
54
  ```imba
41
55
  # app.imba
56
+ import { Localization } from 'imba-localization'
42
57
 
43
- import Localization from 'imba-localization'
44
-
45
- # To create an instance pass the address to the JSON and (optionally) default language
46
- const loc = new Localization("ADDRESS_TO_JSON", "en")
58
+ # Create an instance with the JSON URL and optional default language
59
+ const loc = new Localization("path/to/lang.json", "en")
47
60
 
61
+ # Set up event handlers
48
62
  loc.onready = do
49
- console.log loc['hello'] # Output: "Hello" (or translated value)
50
- console.log loc['goodbye'] # Output: "Goodbye" (or translated value)
51
- # or
52
- console.log loc.hello
53
- # or
54
- console.log loc..hello
63
+ console.log "Localization loaded!"
64
+
65
+ # Access translations in various ways:
66
+ console.log loc.hello # Using dot notation
67
+ console.log loc['goodbye'] # Using bracket notation
68
+ console.log loc['user']['profile'] # Accessing nested properties
55
69
 
56
- loc.onerror = do(msg, err)
57
- console.error "Localization load error:", msg, err
70
+ loc.onerror = do(error, details)
71
+ # The Localization object can return following types of errors:
72
+ # 'no_localization_file' - if there were a problem when downloading JSON file
73
+ # 'no_default_localization' - if there is no localization in the file for the default language
74
+ # 'no_localization_key' - if there is no requiered (from the interface) key in the file
75
+ console.error "Localization error:", error, details
58
76
 
59
- loc.change = do(language)
60
- console.error "Language changed:", language
77
+ loc.onchange = do(lang_key)
78
+ console.log "Language changed to:", lang_key
61
79
 
62
- # Later in your app, you can switch the language:
63
- loc.active = "fr" # Sets the active language to French (if available)
80
+ # Get the current localization code
81
+ console.log loc.active
64
82
 
65
- # The language file can be structured and accessed as usual:
66
- console.log loc['forms']['login']['buttons']['enter']
83
+ # Switch the active language
84
+ loc.active = "fr" # Changes to French if available
85
+
86
+ # Loop through all the localizations
87
+ for key, data of loc.languages
88
+ console.log key, data
89
+
90
+ # Get all the keys for the active language
91
+ console.log loc.languages[loc.active]
67
92
 
68
93
  ```
69
94
 
70
- ## πŸ“„ JSON File Format
95
+ ## πŸ“„ JSON Structure
71
96
 
72
- The localization file (`/lang.json`) should look like this:
97
+ Your localization file should follow this format:
73
98
 
74
99
  ```json
75
100
  {
76
101
  "en": {
77
- "hello": "Hello",
78
- "goodbye": "Goodbye"
102
+ "welcome": "Welcome",
103
+ "goodbye": "Goodbye",
104
+ "user": {
105
+ "profile": "Profile",
106
+ "settings": "Settings"
107
+ }
79
108
  },
80
109
  "fr": {
81
- "hello": "Bonjour",
82
- "goodbye": "Au revoir"
110
+ "welcome": "Bienvenue",
111
+ "goodbye": "Au revoir",
112
+ "user": {
113
+ "profile": "Profil",
114
+ "settings": "Paramètres"
115
+ }
83
116
  }
84
117
  }
85
118
  ```
86
119
 
87
- ## πŸ“˜ Notes
120
+ ## πŸ› οΈ API Reference
121
+
122
+ ### Constructor
123
+
124
+ ```imba
125
+ new Localization(url, default = 'en')
126
+ ```
127
+
128
+ - `url`: Path to your JSON localization file
129
+ - `default`: Fallback language code (defaults to 'en')
130
+
131
+ ### Properties
132
+
133
+ - `active`: Get or set the code of the active language
134
+ - `languages`: Object containing all loaded language data
135
+ - `preferred`: Detected browser language (first 2 characters of `navigator.language`)
136
+
137
+ ### Events
138
+
139
+ - `onready`: Called when localization data is successfully loaded
140
+ - `onerror`: Called when an error occurs (`error`, `details`)
141
+ - `onchange`: Called when the active language changes (`lang_key`)
142
+
143
+ ## 🧩 Components
144
+
145
+ ### LanguageSelector
146
+
147
+ A customizable dropdown component that allows users to select from available in the JSON localization file languages.
148
+
149
+ ```imba
150
+ import { Localization } from 'imba-localization'
151
+ const loc = new Localization("path/to/lang.json", "en")
152
+
153
+ import { LanguageSelector } from 'imba-localization/components'
154
+
155
+ # In your UI component
156
+ tag AppHeader
157
+ <self>
158
+ <LanguageSelector engine=loc> # engine attribute is mandatory
159
+ ```
160
+
161
+ To make this component work as intended, your JSON file will need some adjustments. For each supported language you will need to define the display name for the language and also the country code for the flag to show (for example `en` language is used in `gb` and `us` countries):
162
+
163
+ ```json
164
+ "en": {
165
+ "$": {
166
+ "name": "English",
167
+ "flag": "us"
168
+ }
169
+ }
170
+ ```
171
+
172
+ #### Visual Customization
173
+
174
+ Here are CSS classes (and one variable) you can redefine:
175
+ ```imba
176
+ css
177
+ $ease: 0.5s
178
+ .main
179
+ cursor:pointer
180
+ rd:8px px:15px py:8px
181
+ bgc:light-dark(#000000/10, #FFFFFF/20)
182
+ fw:500 fs:13px
183
+ ead:$ease
184
+ .main-active
185
+ bgc:light-dark(#000000/20, #FFFFFF/30)
186
+ .main-flag
187
+ mr:10px rd:50% w:20px h:20px
188
+ .main-name
189
+ mr:10px
190
+ .main-arrow
191
+ w:16px h:16px ml:auto
192
+ fill:light-dark(#000000,#FFFFFF)
193
+ scale-y:-1
194
+ ead:$ease
195
+ .menu
196
+ t:100% l:50% x:-50% mt:2px rd:8px rd:8px py:5px zi:999
197
+ fw:500 fs:13px
198
+ backdrop-filter:blur(20px)
199
+ bgc:light-dark(#000000/5, #FFFFFF/10)
200
+ ead:$ease
201
+ .menu-item
202
+ cursor:pointer
203
+ d:hflex px:10px py:5px rd:8px m:5px
204
+ bg@hover:light-dark(#000000/10, #FFFFFF/20)
205
+ .menu-item-icon
206
+ h:20px w:20px mr:10px rd:50%
207
+ .menu-item-text
208
+ fs:13px
209
+ ```
210
+ LanguageSelector can be easily customized through CSS and Imba tag (class) inheritance. Here how the above classes can be adjusted via the inheritance:
211
+
212
+ ```imba
213
+ import { LanguageSelector } from 'imba-localization/components'
214
+
215
+ # Create an inheritent class
216
+ tag Languages < LanguageSelector
217
+ css
218
+ $ease: 1s
219
+ .menu-item rd:2px
220
+ .menu-item-icon h:30px w:30px
221
+
222
+ # Using the adjusted component
223
+ tag MyApp
224
+ <self>
225
+ <Languages engine=loc>
226
+ ```
227
+
228
+ #### Flag collections
229
+
230
+ You can redefine the collection of flag icons through the `icons` attribute:
231
+
232
+ ```imba
233
+ <LanguageSelector icons='https://flagicons.lipis.dev/flags/4x3/##.svg'>
234
+ ```
235
+ There are many flag collections out there:
236
+ - https://kapowaz.github.io/square-flags/flags/##.svg (default one)
237
+ - https://hatscripts.github.io/circle-flags/flags/##.svg
238
+ - https://flagcdn.com/##.svg
239
+ - https://cdn.simplelocalize.io/public/v1/flags/##.svg
240
+ - https://cdn.jsdelivr.net/gh/hampusborgos/country-flags@main/svg/##.svg
241
+ - https://flagicons.lipis.dev/flags/4x3/##.svg
242
+
243
+ You can use any other collection you prefer, just change the actual country code to `##` in the url, so the component could replace it with the actual code to obtain a flag for a needed country.
244
+
245
+ #### Dropdown arrow customization
246
+
247
+ You can use any arrow icon you prefer (or remove it though CSS) by passing a tag of the image to the LanguageSelector `arrow` attribute:
248
+
249
+ ```imba
250
+ tag SomeIcon
251
+ <self>
252
+ <svg viewBox="..." xmlns="http://www.w3.org/2000/svg">
253
+ <path d="...">
254
+
255
+
256
+ <LanguageSelector arrow=SomeIcon>
257
+ ```
258
+
259
+ ### ArrowIcon
260
+
261
+ The default arrow icon used in the LanguageSelector component is available as a separate icon (in case for some reason you don't want to use [imba-phosphor-icons](https://www.npmjs.com/package/imba-phosphor-icons) package by Sindre).
262
+
263
+ ```imba
264
+ import {ArrowIcon} from 'imba-localization/components'
88
265
 
89
- - The module attempts to detect the language from `window.navigator.language`, using the first two characters (e.g., `en` from `en-US`).
90
- - If the preferred language isn't available, it uses `'en'` by default.
266
+ tag App
267
+ <self>
268
+ <ArrowIcon>
269
+ css w:20px h:20px stroke:red
270
+ ```
@@ -0,0 +1,4 @@
1
+ declare module 'imba-localization/components' {
2
+ export const LanguageSelector: class;
3
+ export const ArrowIcon: class;
4
+ }
@@ -0,0 +1,49 @@
1
+ export tag ArrowIcon
2
+ <self>
3
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
4
+ <path d="M213.66,165.66a8,8,0,0,1-11.32,0L128,91.31,53.66,165.66a8,8,0,0,1-11.32-11.32l80-80a8,8,0,0,1,11.32,0l80,80A8,8,0,0,1,213.66,165.66Z">
5
+
6
+ export tag LanguageSelector
7
+ engine
8
+ icons = "https://kapowaz.github.io/square-flags/flags/##.svg"
9
+ #dropdown = false
10
+ arrow = ArrowIcon
11
+
12
+ def onselect key
13
+ #dropdown = false
14
+ engine.active = key
15
+
16
+ css
17
+ $ease: 0.5s
18
+ .main rd:8px px:15px py:8px cursor:pointer bgc:light-dark(#000000/10, #FFFFFF/20) fw:500 fs:13px ead:$ease
19
+ .main-active bgc:light-dark(#000000/20, #FFFFFF/30)
20
+ .main-flag mr:10px rd:50% w:20px h:20px
21
+ .main-name mr:10px
22
+ .main-arrow w:16px h:16px fill:light-dark(#000000,#FFFFFF) ml:auto scale-y:-1 ead:$ease
23
+ .menu t:100% l:50% x:-50% zi:999 backdrop-filter:blur(20px) mt:2px rd:8px rd:8px py:5px bgc:light-dark(#000000/5, #FFFFFF/10) fw:500 fs:13px ead:$ease
24
+ .menu-item d:hflex px:10px py:5px rd:8px cursor:pointer bg@hover:light-dark(#000000/10, #FFFFFF/20) m:5px
25
+ .menu-item-icon h:20px w:20px mr:10px rd:50%
26
+ .menu-item-text fs:13px
27
+
28
+ def icon country
29
+ return icons.replace('##',country)
30
+
31
+ def mouseleave e
32
+ const rect = self.getBoundingClientRect!
33
+ const menu = $menu.getBoundingClientRect!
34
+ const inside = e.clientY >= menu.bottom || e.clientY <= rect.top || (e.clientX <= rect.left and e.clientY <= rect.bottom) || (e.clientX <= menu.left and e.clientY >= menu.top) || (e.clientX >= rect.right and e.clientY <= rect.bottom) || (e.clientX >= menu.right and e.clientY >= menu.top)
35
+ #dropdown = !inside
36
+
37
+ <self [pos:rel] @mouseenter=(#dropdown = true) @mouseleave=mouseleave>
38
+ <div.main [pos:rel d:hcc] .main-active=#dropdown>
39
+ <img.main-flag src=icon(engine[engine.active].$.flag)>
40
+ <div.main-name> engine.$.name
41
+ <{arrow}.main-arrow [scale-y:1]=#dropdown>
42
+
43
+ if #dropdown
44
+ <div$menu.menu [pos:abs w:100% > max-content o@off:0] ease>
45
+ for own key, value of engine.languages
46
+ <div.menu-item @click=onselect(key) [d:none]=(key == engine.active)>
47
+ <img.menu-item-icon src=icon(value.$.flag)>
48
+ <span.menu-item-text> value.$.name
49
+
package/index.imba CHANGED
@@ -19,6 +19,7 @@ export class Localization
19
19
  return Reflect.get(target, p, receiver) if self[p]
20
20
  return target.languages[p] if target.languages[p]
21
21
  return target.languages[active][p] if target.languages[active] and target.languages[active][p]
22
+ onerror('no_localization_key', p) if onerror isa Function
22
23
  return ''
23
24
  }
24
25
 
@@ -32,7 +33,7 @@ export class Localization
32
33
  languages = data if data
33
34
  if !languages[default]
34
35
  if onerror isa Function
35
- onerror('no_default_localization')
36
+ onerror('no_default_localization', default)
36
37
  else
37
38
  console.log('There is no Localization for the default language', default)
38
39
  return
package/index.js CHANGED
@@ -1 +1 @@
1
- var P=Symbol.for("#__init__"),J=Symbol.for("#__initor__"),X=Symbol.for("#__inited__"),I=Symbol.for("#__hooks__"),o=Symbol.for("#__patch__"),K=Symbol.for("#has"),Y=Symbol.for("#meta"),Z=Symbol.for("imba"),M=Symbol.for("#__mixin__"),C=Symbol.for("#matcher"),c=Symbol.for("#L"),j=Symbol.for("#appendChild"),d=Symbol.for("#afterVisit"),g=Symbol.for("#beforeReconcile"),i=Symbol.for("#afterReconcile"),y=Symbol.for("##up");var H={IsExtension:1,IsTag:2,HasDescriptors:4,HasSuperCalls:8,HasConstructor:16,HasFields:32,HasMixins:64,HasInitor:128,HasDecorators:256,IsObjectExtension:512},B=new Map,A=globalThis[Z]||={counter:0,classes:B};function F(h,u={}){return B.has(h)||B.set(h,{symbol:Symbol(h.name),parent:Object.getPrototypeOf(h.prototype)?.constructor,for:h,uses:null,inits:null,id:A.counter++,...u}),B.get(h)}function G(h,u){return typeof u==="string"?typeof h===u:u?.[Symbol.hasInstance]?.(h)}function D(h,u){if(!h||!u)return!1;if(h.get)return u.get===h.get;if(h.set)return u.set===h.set;if(h.value)return h.value===u.value}function L(h,u,f,n={}){let z=h.constructor;if(!f&&u){if(f=Object.getOwnPropertyDescriptors(u),delete f.constructor,f[P])console.warn(`Cannot define plain fields when extending class ${z.name}`),delete f[P]}let v=F(z);if(v&&v.augments){let R=new Map;for(let r of Object.keys(f)){let S=Object.getOwnPropertyDescriptor(h,r);for(let w of v.augments){let q=R.get(w);q||R.set(w,q={});let E=Object.getOwnPropertyDescriptor(w.prototype,r);if(E&&!D(S,E))console.warn("wont extend",r,E,S);else q[r]=f[r]}}for(let[r,S]of R)if(Object.keys(S).length)L(r.prototype,null,S)}return Object.defineProperties(h,f),h}function N(h,u){let f=F(h),n=F(u);if(n.parent){if(!(h.prototype instanceof n.parent))throw new Error(`Mixin ${u.name} has superclass not present in target class`)}if(!n.augments){n.augments=new Set;let v=n.ref=Symbol(u.name),R=Object[Symbol.hasInstance];u.prototype[v]=!0,Object.defineProperty(u,Symbol.hasInstance,{value:function(r){return this===u?r&&!!r[v]:R.call(this,r)}})}if(h.prototype[n.ref])return h;if(n.uses)for(let v of n.uses)N(h,v);n.augments.add(h),f.uses||=[],f.uses.push(u);let z=Object.getOwnPropertyDescriptors(u.prototype);if(delete z.constructor,z[P])f.inits||=[],f.inits.push(u.prototype[P]),delete z[P];if(Object.defineProperties(h.prototype,z),u?.mixed instanceof Function)u.mixed(h);return h}var T={cache:{},self:null,target:null,proxy:new Proxy({},{apply:(h,u,...f)=>{return T.target[u].apply(T.self,f)},get:(h,u)=>{return Reflect.get(T.target,u,T.self)},set:(h,u,f,n)=>{return Reflect.set(T.target,u,f,T.self)}})};function Q(h,u,f,n,z=null){let v=Object.getPrototypeOf(h.prototype),R=n&H.HasMixins,r;if(R)B.set(h,B.get(v.constructor)),v=Object.getPrototypeOf(v);if(z){let w=n&H.IsObjectExtension?z:z.prototype,q=F(h);if(q.uses){if(z===w)console.warn("Cannot extend object with mixins");for(let E of q.uses)N(z,E)}if(n&H.HasSuperCalls)T.cache[u]=Object.create(Object.getPrototypeOf(w),Object.getOwnPropertyDescriptors(w));return L(w,h.prototype),z}let S=v?.constructor;if(r=F(h,{symbol:u}),Object.defineProperty(h,Y,{value:r,enumerable:!1,configurable:!0}),f&&h.name!==f)Object.defineProperty(h,"name",{value:f,configurable:!0});if(r.flags=n,n&H.HasConstructor)h.prototype[J]=u;if(r.uses)for(let w of r.uses)w.mixes?.(h);if(S?.inherited instanceof Function)S.inherited(h);return h}function V(h,u){if(h[J]===u)h[X]?.(),h[I]&&h[I].inited(h)}var U=Symbol.for("#active"),W=Symbol();class O{[P](h=null,u=!0,f=!0){var n;this.onready=h?h.onready:void 0,this.onerror=h?h.onerror:void 0,this.onchange=h?h.onchange:void 0,this.languages=h&&(n=h.languages)!==void 0?n:{},this.preferred=h&&(n=h.preferred)!==void 0?n:(window?.navigator?.language||"en-US").slice(0,2),this[U]=h?h[U]:void 0,this.default=h?h.default:void 0}constructor(h,u="en"){var f=this;return this[P](),this.default=u,window.fetch(h).then(function(n){return n.json()}).then(function(n){return f._finalize(n,void 0)}).catch(function(n){return f._finalize(void 0,n)}),new Proxy(this,{get:function(n,z,v){if(f[z])return Reflect.get(n,z,v);if(n.languages[z])return n.languages[z];if(n.languages[f.active]&&n.languages[f.active][z])return n.languages[f.active][z];return""}});V(this,W)}_finalize(h,u){if(u){if(G(this.onerror,Function))this.onerror("no_localization_file",u);else console.log("Localization file was not loaded",u);return}if(h)this.languages=h;if(!this.languages[this.default]){if(G(this.onerror,Function))this.onerror("no_default_localization");else console.log("There is no Localization for the default language",this.default);return}if(this.active=this.preferred,G(this.onready,Function))return this.onready()}get active(){return this.languages[this[U]]?this[U]:this.default}set active(h){if(h&&this.languages[h])this[U]=h;else this[U]=this.languages[this.preferred]?this.preferred:this.default;if(G(this.onchange,Function))this.onchange(this[U])}static{Q(this,W,"Localization",16)}}export{O as Localization};
1
+ var S=Symbol.for("#__init__"),I=Symbol.for("#__initor__"),W=Symbol.for("#__inited__"),H=Symbol.for("#__hooks__"),O=Symbol.for("#__patch__"),K=Symbol.for("#has"),X=Symbol.for("#meta"),Y=Symbol.for("imba"),c=Symbol.for("#__mixin__"),M=Symbol.for("#matcher"),C=Symbol.for("#L"),j=Symbol.for("#appendChild"),i=Symbol.for("#afterVisit"),d=Symbol.for("#beforeReconcile"),g=Symbol.for("#afterReconcile"),y=Symbol.for("##up");var G={IsExtension:1,IsTag:2,HasDescriptors:4,HasSuperCalls:8,HasConstructor:16,HasFields:32,HasMixins:64,HasInitor:128,HasDecorators:256,IsObjectExtension:512},U=new Map,Z=globalThis[Y]||={counter:0,classes:U};function E(h,n={}){return U.has(h)||U.set(h,{symbol:Symbol(h.name),parent:Object.getPrototypeOf(h.prototype)?.constructor,for:h,uses:null,inits:null,id:Z.counter++,...n}),U.get(h)}function q(h,n){return typeof n==="string"?typeof h===n:n?.[Symbol.hasInstance]?.(h)}function A(h,n){if(!h||!n)return!1;if(h.get)return n.get===h.get;if(h.set)return n.set===h.set;if(h.value)return h.value===n.value}function J(h,n,f,u={}){let r=h.constructor;if(!f&&n){if(f=Object.getOwnPropertyDescriptors(n),delete f.constructor,f[S])console.warn(`Cannot define plain fields when extending class ${r.name}`),delete f[S]}let o=E(r);if(o&&o.augments){let F=new Map;for(let z of Object.keys(f)){let w=Object.getOwnPropertyDescriptor(h,z);for(let v of o.augments){let T=F.get(v);T||F.set(v,T={});let B=Object.getOwnPropertyDescriptor(v.prototype,z);if(B&&!A(w,B))console.warn("wont extend",z,B,w);else T[z]=f[z]}}for(let[z,w]of F)if(Object.keys(w).length)J(z.prototype,null,w)}return Object.defineProperties(h,f),h}function L(h,n){let f=E(h),u=E(n);if(u.parent){if(!(h.prototype instanceof u.parent))throw new Error(`Mixin ${n.name} has superclass not present in target class`)}if(!u.augments){u.augments=new Set;let o=u.ref=Symbol(n.name),F=Object[Symbol.hasInstance];n.prototype[o]=!0,Object.defineProperty(n,Symbol.hasInstance,{value:function(z){return this===n?z&&!!z[o]:F.call(this,z)}})}if(h.prototype[u.ref])return h;if(u.uses)for(let o of u.uses)L(h,o);u.augments.add(h),f.uses||=[],f.uses.push(n);let r=Object.getOwnPropertyDescriptors(n.prototype);if(delete r.constructor,r[S])f.inits||=[],f.inits.push(n.prototype[S]),delete r[S];if(Object.defineProperties(h.prototype,r),n?.mixed instanceof Function)n.mixed(h);return h}var P={cache:{},self:null,target:null,proxy:new Proxy({},{apply:(h,n,...f)=>{return P.target[n].apply(P.self,f)},get:(h,n)=>{return Reflect.get(P.target,n,P.self)},set:(h,n,f,u)=>{return Reflect.set(P.target,n,f,P.self)}})};function N(h,n,f,u,r=null){let o=Object.getPrototypeOf(h.prototype),F=u&G.HasMixins,z;if(F)U.set(h,U.get(o.constructor)),o=Object.getPrototypeOf(o);if(r){let v=u&G.IsObjectExtension?r:r.prototype,T=E(h);if(T.uses){if(r===v)console.warn("Cannot extend object with mixins");for(let B of T.uses)L(r,B)}if(u&G.HasSuperCalls)P.cache[n]=Object.create(Object.getPrototypeOf(v),Object.getOwnPropertyDescriptors(v));return J(v,h.prototype),r}let w=o?.constructor;if(z=E(h,{symbol:n}),Object.defineProperty(h,X,{value:z,enumerable:!1,configurable:!0}),f&&h.name!==f)Object.defineProperty(h,"name",{value:f,configurable:!0});if(z.flags=u,u&G.HasConstructor)h.prototype[I]=n;if(z.uses)for(let v of z.uses)v.mixes?.(h);if(w?.inherited instanceof Function)w.inherited(h);return h}function Q(h,n){if(h[I]===n)h[W]?.(),h[H]&&h[H].inited(h)}var R=Symbol.for("#active"),V=Symbol();class D{[S](h=null,n=!0,f=!0){var u;this.onready=h?h.onready:void 0,this.onerror=h?h.onerror:void 0,this.onchange=h?h.onchange:void 0,this.languages=h&&(u=h.languages)!==void 0?u:{},this.preferred=h&&(u=h.preferred)!==void 0?u:(window?.navigator?.language||"en-US").slice(0,2),this[R]=h?h[R]:void 0,this.default=h?h.default:void 0}constructor(h,n="en"){var f=this;return this[S](),this.default=n,window.fetch(h).then(function(u){return u.json()}).then(function(u){return f._finalize(u,void 0)}).catch(function(u){return f._finalize(void 0,u)}),new Proxy(this,{get:function(u,r,o){if(f[r])return Reflect.get(u,r,o);if(u.languages[r])return u.languages[r];if(u.languages[f.active]&&u.languages[f.active][r])return u.languages[f.active][r];if(q(f.onerror,Function))f.onerror("no_localization_key",r);return""}});Q(this,V)}_finalize(h,n){if(n){if(q(this.onerror,Function))this.onerror("no_localization_file",n);else console.log("Localization file was not loaded",n);return}if(h)this.languages=h;if(!this.languages[this.default]){if(q(this.onerror,Function))this.onerror("no_default_localization",this.default);else console.log("There is no Localization for the default language",this.default);return}if(this.active=this.preferred,q(this.onready,Function))return this.onready()}get active(){return this.languages[this[R]]?this[R]:this.default}set active(h){if(h&&this.languages[h])this[R]=h;else this[R]=this.languages[this.preferred]?this.preferred:this.default;if(q(this.onchange,Function))this.onchange(this[R])}static{N(this,V,"Localization",16)}}export{D as Localization};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imba-localization",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/HeapVoid/imba-localization.git"
@@ -22,6 +22,8 @@
22
22
  "type": "module",
23
23
  "files": [
24
24
  "index.imba",
25
- "index.js"
25
+ "index.js",
26
+ "components.imba",
27
+ "components.d.ts"
26
28
  ]
27
29
  }