@gringow/gringow-shadow 0.0.2 → 0.0.4
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 +272 -29
- package/dist/gringow-store.mjs +2 -2
- package/dist/index.mjs +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,57 +1,300 @@
|
|
|
1
1
|
# @gringow/gringow-shadow
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@gringow/gringow-shadow)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
Lightweight Web Component layer for Gringow translations. Provides the `<g-gringow>` custom element, translation store, and language change events for vanilla JavaScript projects. This is the foundation layer used by [@gringow/gringow-react](https://www.npmjs.com/package/@gringow/gringow-react).
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- 🎯 **Custom Element** - `<g-gringow>` for declarative translations
|
|
11
|
+
- 🗂️ **Translation Store** - Singleton cache manager with language awareness
|
|
12
|
+
- 📡 **Language Events** - Type-safe language change broadcasting
|
|
13
|
+
- 🪶 **Zero Dependencies** - Pure Web Components API
|
|
14
|
+
- ⚡ **Framework Agnostic** - Works with vanilla JS, React, Vue, etc.
|
|
15
|
+
- 🔄 **Smart Caching** - Memoized cache fetching and lookup
|
|
10
16
|
|
|
11
17
|
## Installation
|
|
18
|
+
|
|
12
19
|
```bash
|
|
20
|
+
# Using pnpm
|
|
13
21
|
pnpm add @gringow/gringow-shadow
|
|
14
|
-
|
|
15
|
-
#
|
|
22
|
+
|
|
23
|
+
# Using npm
|
|
24
|
+
npm install @gringow/gringow-shadow
|
|
25
|
+
|
|
26
|
+
# Using yarn
|
|
27
|
+
yarn add @gringow/gringow-shadow
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
### Vanilla HTML Setup
|
|
33
|
+
|
|
34
|
+
```html
|
|
35
|
+
<!DOCTYPE html>
|
|
36
|
+
<html lang="en">
|
|
37
|
+
<head>
|
|
38
|
+
<meta name="gringow-cache-url" content="/gringow/gringow.json">
|
|
39
|
+
</head>
|
|
40
|
+
<body>
|
|
41
|
+
<g-gringow data-cache-id="grw_abc123" data-flatten="Hello world"></g-gringow>
|
|
42
|
+
|
|
43
|
+
<button id="btn-pt">Português</button>
|
|
44
|
+
<button id="btn-fr">Français</button>
|
|
45
|
+
|
|
46
|
+
<script type="module">
|
|
47
|
+
import { GringowComponent, GringowStore, LanguageChangeEvent } from '@gringow/gringow-shadow'
|
|
48
|
+
|
|
49
|
+
// Configure store
|
|
50
|
+
GringowStore.cacheUrl = '/gringow/gringow.json'
|
|
51
|
+
GringowStore.language = 'en-US'
|
|
52
|
+
await GringowStore.fetchCache()
|
|
53
|
+
|
|
54
|
+
// Register custom element
|
|
55
|
+
GringowComponent.defaults = { store: GringowStore }
|
|
56
|
+
customElements.define(GringowComponent.GRINGOW_ELEMENT_NAME, GringowComponent)
|
|
57
|
+
|
|
58
|
+
// Handle language changes
|
|
59
|
+
document.getElementById('btn-pt').onclick = () => {
|
|
60
|
+
dispatchEvent(LanguageChangeEvent.create('pt-BR'))
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
document.getElementById('btn-fr').onclick = () => {
|
|
64
|
+
dispatchEvent(LanguageChangeEvent.create('fr-CA'))
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Listen to language changes
|
|
68
|
+
addEventListener(LanguageChangeEvent.EVENT_NAME, (event) => {
|
|
69
|
+
console.log('Language changed to:', event.detail.lang)
|
|
70
|
+
})
|
|
71
|
+
</script>
|
|
72
|
+
</body>
|
|
73
|
+
</html>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Component API
|
|
77
|
+
|
|
78
|
+
### `<g-gringow>` Custom Element
|
|
79
|
+
|
|
80
|
+
Declarative translation component that reads from the cache and updates on language changes.
|
|
81
|
+
|
|
82
|
+
#### Attributes
|
|
83
|
+
|
|
84
|
+
- **`data-cache-id`** (required) - Cache ID from `gringow.json` (e.g., `grw_abc123`)
|
|
85
|
+
- **`data-flatten`** (required) - Original flattened string used as fallback
|
|
86
|
+
- **`data-replacements`** (optional) - JSON array for interpolation (e.g., `'["Alice", 5]'`)
|
|
87
|
+
|
|
88
|
+
#### Example with Replacements
|
|
89
|
+
|
|
90
|
+
```html
|
|
91
|
+
<!-- Cache entry: "Hello {0}, you have {1} messages" -->
|
|
92
|
+
<g-gringow
|
|
93
|
+
data-cache-id="grw_msg456"
|
|
94
|
+
data-flatten="Hello {name}, you have {count} messages"
|
|
95
|
+
data-replacements='["Alice", 5]'>
|
|
96
|
+
</g-gringow>
|
|
97
|
+
<!-- Renders: "Hello Alice, you have 5 messages" -->
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### GringowStore (Singleton)
|
|
101
|
+
|
|
102
|
+
Central cache manager for fetching and accessing translations.
|
|
103
|
+
|
|
104
|
+
#### Properties
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
// Cache file URL (auto-detects from <meta> or <html data-gringow-cache-url>)
|
|
108
|
+
GringowStore.cacheUrl: string | null
|
|
109
|
+
|
|
110
|
+
// Active language (defaults to document.documentElement.lang)
|
|
111
|
+
GringowStore.language: string | null
|
|
112
|
+
|
|
113
|
+
// Cached translations object
|
|
114
|
+
GringowStore.cache: GringowCache | null
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### Methods
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
// Fetch and memoize cache from cacheUrl
|
|
121
|
+
await GringowStore.fetchCache(): Promise<void>
|
|
122
|
+
|
|
123
|
+
// Get translated string for active language
|
|
124
|
+
GringowStore.getCacheItem(cacheId: string): string | null
|
|
125
|
+
|
|
126
|
+
// Manual cache setter
|
|
127
|
+
GringowStore.setCache(cache: GringowCache): void
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
#### Configuration Priority
|
|
131
|
+
|
|
132
|
+
The store resolves `cacheUrl` in this order:
|
|
133
|
+
|
|
134
|
+
1. `GringowStore.cacheUrl` (programmatic)
|
|
135
|
+
2. `<meta name="gringow-cache-url" content="/path/to/cache.json">`
|
|
136
|
+
3. `<html data-gringow-cache-url="/path/to/cache.json">`
|
|
137
|
+
|
|
138
|
+
### LanguageChangeEvent
|
|
139
|
+
|
|
140
|
+
Custom event for broadcasting language changes across components.
|
|
141
|
+
|
|
142
|
+
#### Usage
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
// Dispatch language change
|
|
146
|
+
dispatchEvent(LanguageChangeEvent.create('pt-BR'))
|
|
147
|
+
|
|
148
|
+
// Listen for changes
|
|
149
|
+
addEventListener(LanguageChangeEvent.EVENT_NAME, (event) => {
|
|
150
|
+
console.log('New language:', event.detail.lang)
|
|
151
|
+
// event.detail.lang === 'pt-BR'
|
|
152
|
+
})
|
|
16
153
|
```
|
|
17
154
|
|
|
18
|
-
|
|
155
|
+
#### Constants
|
|
156
|
+
|
|
157
|
+
- **`LanguageChangeEvent.EVENT_NAME`** - `'gringow:language-change'`
|
|
158
|
+
- **`LanguageChangeEvent.create(lang: string)`** - Factory method for events
|
|
159
|
+
|
|
160
|
+
## Advanced Examples
|
|
161
|
+
|
|
162
|
+
### Dynamic Content with Interpolation
|
|
163
|
+
|
|
19
164
|
```html
|
|
20
165
|
<script type="module">
|
|
21
|
-
import { GringowComponent, GringowStore
|
|
166
|
+
import { GringowComponent, GringowStore } from '@gringow/gringow-shadow'
|
|
22
167
|
|
|
23
168
|
GringowStore.cacheUrl = '/gringow/gringow.json'
|
|
24
169
|
GringowStore.language = 'en-US'
|
|
25
170
|
await GringowStore.fetchCache()
|
|
26
171
|
|
|
27
|
-
// Wire the custom element to the store once
|
|
28
172
|
GringowComponent.defaults = { store: GringowStore }
|
|
29
|
-
customElements.define(
|
|
173
|
+
customElements.define('g-gringow', GringowComponent)
|
|
174
|
+
|
|
175
|
+
// Dynamically create element with replacements
|
|
176
|
+
const element = document.createElement('g-gringow')
|
|
177
|
+
element.setAttribute('data-cache-id', 'grw_welcome')
|
|
178
|
+
element.setAttribute('data-flatten', 'Welcome back, {name}!')
|
|
179
|
+
element.setAttribute('data-replacements', JSON.stringify(['Alice']))
|
|
180
|
+
document.body.appendChild(element)
|
|
181
|
+
</script>
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Multiple Language Switcher
|
|
185
|
+
|
|
186
|
+
```html
|
|
187
|
+
<nav>
|
|
188
|
+
<button data-lang="en-US">English</button>
|
|
189
|
+
<button data-lang="pt-BR">Português</button>
|
|
190
|
+
<button data-lang="fr-CA">Français</button>
|
|
191
|
+
<button data-lang="es-ES">Español</button>
|
|
192
|
+
</nav>
|
|
193
|
+
|
|
194
|
+
<main>
|
|
195
|
+
<g-gringow data-cache-id="grw_title" data-flatten="Welcome"></g-gringow>
|
|
196
|
+
<g-gringow data-cache-id="grw_desc" data-flatten="Choose your language"></g-gringow>
|
|
197
|
+
</main>
|
|
198
|
+
|
|
199
|
+
<script type="module">
|
|
200
|
+
import { GringowComponent, GringowStore, LanguageChangeEvent } from '@gringow/gringow-shadow'
|
|
201
|
+
|
|
202
|
+
// Setup
|
|
203
|
+
GringowStore.cacheUrl = '/gringow/gringow.json'
|
|
204
|
+
GringowStore.language = document.documentElement.lang || 'en-US'
|
|
205
|
+
await GringowStore.fetchCache()
|
|
206
|
+
|
|
207
|
+
GringowComponent.defaults = { store: GringowStore }
|
|
208
|
+
customElements.define('g-gringow', GringowComponent)
|
|
30
209
|
|
|
31
|
-
//
|
|
32
|
-
|
|
210
|
+
// Wire language buttons
|
|
211
|
+
document.querySelectorAll('[data-lang]').forEach(btn => {
|
|
212
|
+
btn.onclick = () => {
|
|
213
|
+
const lang = btn.dataset.lang
|
|
214
|
+
document.documentElement.lang = lang
|
|
215
|
+
dispatchEvent(LanguageChangeEvent.create(lang))
|
|
216
|
+
}
|
|
217
|
+
})
|
|
33
218
|
</script>
|
|
219
|
+
```
|
|
34
220
|
|
|
35
|
-
|
|
36
|
-
|
|
221
|
+
### Framework Integration (Vue/Svelte/etc)
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
// utils/gringow.ts
|
|
225
|
+
import { GringowComponent, GringowStore, LanguageChangeEvent } from '@gringow/gringow-shadow'
|
|
226
|
+
|
|
227
|
+
export async function initGringow(cacheUrl: string, initialLang: string) {
|
|
228
|
+
GringowStore.cacheUrl = cacheUrl
|
|
229
|
+
GringowStore.language = initialLang
|
|
230
|
+
await GringowStore.fetchCache()
|
|
231
|
+
|
|
232
|
+
GringowComponent.defaults = { store: GringowStore }
|
|
233
|
+
|
|
234
|
+
if (!customElements.get('g-gringow')) {
|
|
235
|
+
customElements.define('g-gringow', GringowComponent)
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export function changeLanguage(lang: string) {
|
|
240
|
+
dispatchEvent(LanguageChangeEvent.create(lang))
|
|
241
|
+
}
|
|
37
242
|
```
|
|
38
243
|
|
|
39
|
-
|
|
40
|
-
flattened string used as a fallback.
|
|
244
|
+
## Module Exports
|
|
41
245
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
246
|
+
The package provides granular exports for tree-shaking:
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
// Main export (all components)
|
|
250
|
+
import { GringowComponent, GringowStore, LanguageChangeEvent } from '@gringow/gringow-shadow'
|
|
251
|
+
|
|
252
|
+
// Individual exports
|
|
253
|
+
import { GringowComponent } from '@gringow/gringow-shadow/component'
|
|
254
|
+
import { GringowStore } from '@gringow/gringow-shadow/store'
|
|
255
|
+
import { LanguageChangeEvent } from '@gringow/gringow-shadow/event'
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Development
|
|
49
259
|
|
|
50
|
-
## Development scripts
|
|
51
260
|
```bash
|
|
52
|
-
|
|
53
|
-
pnpm
|
|
261
|
+
# Install dependencies
|
|
262
|
+
pnpm install
|
|
263
|
+
|
|
264
|
+
# Build the package
|
|
265
|
+
pnpm run build
|
|
266
|
+
|
|
267
|
+
# Watch mode for development
|
|
268
|
+
pnpm run watch
|
|
54
269
|
```
|
|
55
270
|
|
|
271
|
+
## Browser Compatibility
|
|
272
|
+
|
|
273
|
+
Built on Web Components standards:
|
|
274
|
+
- Custom Elements v1
|
|
275
|
+
- Shadow DOM v1
|
|
276
|
+
- ES2020+ modules
|
|
277
|
+
|
|
278
|
+
**Supported browsers**: Chrome 54+, Firefox 63+, Safari 10.1+, Edge 79+
|
|
279
|
+
|
|
280
|
+
## Related Packages
|
|
281
|
+
|
|
282
|
+
- **[@gringow/gringow](https://www.npmjs.com/package/@gringow/gringow)** - Core translation library
|
|
283
|
+
- **[@gringow/gringow-react](https://www.npmjs.com/package/@gringow/gringow-react)** - React integration (built on this package)
|
|
284
|
+
- **[@gringow/gringow-vite](https://www.npmjs.com/package/@gringow/gringow-vite)** - Vite plugin
|
|
285
|
+
- **[@gringow/cli](https://www.npmjs.com/package/@gringow/gringow-cli)** - CLI tool
|
|
286
|
+
- **[@gringow/gringow-nextjs](https://www.npmjs.com/package/@gringow/gringow-nextjs)** - Next.js plugin (experimental)
|
|
287
|
+
|
|
288
|
+
## Resources
|
|
289
|
+
|
|
290
|
+
- [Documentation](https://gringow.dev)
|
|
291
|
+
- [GitHub Repository](https://github.com/rntgspr/gringow)
|
|
292
|
+
- [Example: Vanilla HTML](https://github.com/rntgspr/gringow/tree/main/example-html)
|
|
293
|
+
|
|
56
294
|
## License
|
|
57
|
-
|
|
295
|
+
|
|
296
|
+
MIT © [Renato Gaspar](https://github.com/rntgspr)
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
**Questions?** Open an issue on [GitHub](https://github.com/rntgspr/gringow/issues)
|
package/dist/gringow-store.mjs
CHANGED
|
@@ -11,7 +11,7 @@ var GringowStoreSingleton = class _GringowStoreSingleton {
|
|
|
11
11
|
return _GringowStoreSingleton.instance;
|
|
12
12
|
}
|
|
13
13
|
get cacheUrl() {
|
|
14
|
-
return this.#cacheUrl ?? document
|
|
14
|
+
return this.#cacheUrl ?? globalThis?.document?.head?.querySelector('meta[name="gringow-cache-url"]')?.getAttribute("content") ?? globalThis?.document?.documentElement?.getAttribute("data-gringow-cache-url");
|
|
15
15
|
}
|
|
16
16
|
set cacheUrl(value) {
|
|
17
17
|
if (typeof value !== "string" || value.trim().length <= 0) return;
|
|
@@ -28,7 +28,7 @@ var GringowStoreSingleton = class _GringowStoreSingleton {
|
|
|
28
28
|
this.#language = value;
|
|
29
29
|
}
|
|
30
30
|
get language() {
|
|
31
|
-
return this.#language ?? document?.documentElement?.getAttribute("lang");
|
|
31
|
+
return this.#language ?? globalThis?.document?.head?.querySelector('meta[name="gringow-default-language"]')?.getAttribute("content") ?? globalThis?.document?.documentElement?.getAttribute("lang");
|
|
32
32
|
}
|
|
33
33
|
constructor() {
|
|
34
34
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -94,7 +94,7 @@ var GringowStoreSingleton = class _GringowStoreSingleton {
|
|
|
94
94
|
return _GringowStoreSingleton.instance;
|
|
95
95
|
}
|
|
96
96
|
get cacheUrl() {
|
|
97
|
-
return this.#cacheUrl ?? document
|
|
97
|
+
return this.#cacheUrl ?? globalThis?.document?.head?.querySelector('meta[name="gringow-cache-url"]')?.getAttribute("content") ?? globalThis?.document?.documentElement?.getAttribute("data-gringow-cache-url");
|
|
98
98
|
}
|
|
99
99
|
set cacheUrl(value) {
|
|
100
100
|
if (typeof value !== "string" || value.trim().length <= 0) return;
|
|
@@ -111,7 +111,7 @@ var GringowStoreSingleton = class _GringowStoreSingleton {
|
|
|
111
111
|
this.#language = value;
|
|
112
112
|
}
|
|
113
113
|
get language() {
|
|
114
|
-
return this.#language ?? document?.documentElement?.getAttribute("lang");
|
|
114
|
+
return this.#language ?? globalThis?.document?.head?.querySelector('meta[name="gringow-default-language"]')?.getAttribute("content") ?? globalThis?.document?.documentElement?.getAttribute("lang");
|
|
115
115
|
}
|
|
116
116
|
constructor() {
|
|
117
117
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gringow/gringow-shadow",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "A HTML class for Gringow AI-powered translation tool",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"globby": "14.1.0",
|
|
55
55
|
"vite": "7.0.0",
|
|
56
|
-
"@gringow/gringow": "0.1.
|
|
56
|
+
"@gringow/gringow": "0.1.4"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@types/node": "22.15.0",
|