@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 CHANGED
@@ -1,57 +1,300 @@
1
1
  # @gringow/gringow-shadow
2
2
 
3
- Lightweight Web Component layer used by the React bindings. It ships the `<g-gringow>` custom element, a minimal
4
- translation store, and a typed language change event so you can render Gringow translations without React.
3
+ [![npm version](https://img.shields.io/npm/v/@gringow/gringow-shadow)](https://www.npmjs.com/package/@gringow/gringow-shadow)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
5
5
 
6
- ## What it provides
7
- - `<g-gringow>` custom element that renders translated text from a Gringow cache file
8
- - `GringowStore` singleton to fetch and hold the cache (URL + language aware)
9
- - `LanguageChangeEvent` helper to broadcast language switches
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
- # npm install @gringow/gringow-shadow
15
- # yarn add @gringow/gringow-shadow
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
- ## Quick start (vanilla HTML)
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, LanguageChangeEvent } from '@gringow/gringow-shadow'
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(GringowComponent.GRINGOW_ELEMENT_NAME, GringowComponent)
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
- // Listen to language changes
32
- addEventListener(LanguageChangeEvent.EVENT_NAME, (event) => console.log(event.detail.lang))
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
- <g-gringow data-cache-id="grw-abc123" data-flatten="Hello world"></g-gringow>
36
- <button onclick="dispatchEvent(LanguageChangeEvent.create('pt-BR'))">pt-BR</button>
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
- `data-cache-id` must match the cache entry key from `gringow/gringow.json`, and `data-flatten` is the original
40
- flattened string used as a fallback.
244
+ ## Module Exports
41
245
 
42
- ## Store & events
43
- - `GringowStore.cacheUrl` — can also be provided via `<meta name="gringow-cache-url">` or `data-gringow-cache-url` on
44
- `<html>`.
45
- - `GringowStore.language` defaults to `document.documentElement.lang` when not set.
46
- - `GringowStore.fetchCache()` fetches and memoizes the cache file (throws if URL or language is missing).
47
- - `GringowStore.getCacheItem(cacheId)` — returns the translated string for the active language or `null`.
48
- - `LanguageChangeEvent.EVENT_NAME` and `LanguageChangeEvent.create(lang)` — helper to dispatch language changes.
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
- pnpm run build # Emit dist/ with tsup
53
- pnpm run watch # Continuous rebuild for local development
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
- MIT © Renato Gaspar
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)
@@ -11,7 +11,7 @@ var GringowStoreSingleton = class _GringowStoreSingleton {
11
11
  return _GringowStoreSingleton.instance;
12
12
  }
13
13
  get cacheUrl() {
14
- return this.#cacheUrl ?? document.head.querySelector('meta[name="gringow-cache-url"]')?.getAttribute("content") ?? document.documentElement.getAttribute("data-gringow-cache-url");
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.head.querySelector('meta[name="gringow-cache-url"]')?.getAttribute("content") ?? document.documentElement.getAttribute("data-gringow-cache-url");
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.2",
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.3"
56
+ "@gringow/gringow": "0.1.4"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@types/node": "22.15.0",