@verbadev/js 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/README.md +265 -0
- package/dist/index.d.mts +84 -0
- package/dist/index.d.ts +84 -0
- package/dist/index.js +1 -0
- package/dist/index.mjs +1 -0
- package/package.json +42 -0
package/README.md
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# @verbadev/js
|
|
2
|
+
|
|
3
|
+
Official JavaScript SDK for [Verba](https://verba.dev) - Translation Management System.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @verbadev/js
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { Verba } from '@verbadev/js'
|
|
15
|
+
|
|
16
|
+
const verba = new Verba({
|
|
17
|
+
projectId: 'your-project-id',
|
|
18
|
+
publicKey: 'pk_your-public-key',
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
// Get a translation
|
|
22
|
+
const text = verba.t('welcome.message')
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Configuration
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
const verba = new Verba({
|
|
29
|
+
projectId: string, // Required - Your project ID from the dashboard
|
|
30
|
+
publicKey: string, // Required - Your public key (safe for client-side)
|
|
31
|
+
locale?: string, // Optional - defaults to auto-detection from browser
|
|
32
|
+
baseUrl?: string, // Optional - API base URL (default: 'https://verba.dev')
|
|
33
|
+
})
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Locale Auto-Detection
|
|
37
|
+
|
|
38
|
+
By default, the SDK automatically detects the user's locale from the browser (`navigator.language`) and matches it against your project's available locales.
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
// Auto-detect (default behavior)
|
|
42
|
+
const verba = new Verba({ projectId, publicKey })
|
|
43
|
+
|
|
44
|
+
// Explicit auto-detect
|
|
45
|
+
const verba = new Verba({ projectId, publicKey, locale: 'auto' })
|
|
46
|
+
|
|
47
|
+
// Override with specific locale
|
|
48
|
+
const verba = new Verba({ projectId, publicKey, locale: 'es' })
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Matching logic:**
|
|
52
|
+
1. Exact match (e.g., `en-US` → `en-US`)
|
|
53
|
+
2. Base language match (e.g., `en-US` → `en`)
|
|
54
|
+
3. Falls back to project's default locale if no match
|
|
55
|
+
|
|
56
|
+
## API Reference
|
|
57
|
+
|
|
58
|
+
### `verba.t(key, defaultValue?, params?)`
|
|
59
|
+
|
|
60
|
+
Get a translation for the current locale with optional interpolation.
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// Basic usage
|
|
64
|
+
verba.t('welcome.message')
|
|
65
|
+
|
|
66
|
+
// With default value (auto-creates missing keys)
|
|
67
|
+
verba.t('greeting', 'Hello!')
|
|
68
|
+
|
|
69
|
+
// With interpolation params
|
|
70
|
+
verba.t('greeting', { name: 'Łukasz' })
|
|
71
|
+
// 'Hello, {name}!' → 'Hello, Łukasz!'
|
|
72
|
+
|
|
73
|
+
// With both default value and params
|
|
74
|
+
verba.t('greeting', 'Hello, {name}!', { name: 'Łukasz' })
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Flexible signature:**
|
|
78
|
+
- `t(key)` - just the key
|
|
79
|
+
- `t(key, defaultValue)` - with fallback string
|
|
80
|
+
- `t(key, params)` - with interpolation params (object)
|
|
81
|
+
- `t(key, defaultValue, params)` - with both
|
|
82
|
+
|
|
83
|
+
**Parameters:**
|
|
84
|
+
- `key` (string) - The translation key
|
|
85
|
+
- `defaultValue` (string, optional) - Fallback value if key doesn't exist
|
|
86
|
+
- `params` (object, optional) - Values to interpolate into `{placeholder}` tokens
|
|
87
|
+
|
|
88
|
+
**Returns:** The translated string with interpolation applied.
|
|
89
|
+
|
|
90
|
+
**Auto-creation:** When you call `t()` with a `defaultValue` and the key doesn't exist, the SDK automatically:
|
|
91
|
+
1. Returns the `defaultValue` immediately
|
|
92
|
+
2. Creates the key in Verba in the background
|
|
93
|
+
3. Triggers AI translation to all your project's locales
|
|
94
|
+
|
|
95
|
+
This enables a powerful workflow where you can write code first and translations are created on-the-fly.
|
|
96
|
+
|
|
97
|
+
### `verba.setLocale(locale)`
|
|
98
|
+
|
|
99
|
+
Change the active locale.
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
verba.setLocale('es')
|
|
103
|
+
const text = verba.t('welcome.message') // Returns Spanish translation
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### `verba.getLocale()`
|
|
107
|
+
|
|
108
|
+
Get the current locale.
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
const locale = verba.getLocale() // 'en'
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### `verba.getLocales()`
|
|
115
|
+
|
|
116
|
+
Get all available locales for the project.
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
const locales = verba.getLocales() // ['en', 'es', 'fr']
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### `verba.getDefaultLocale()`
|
|
123
|
+
|
|
124
|
+
Get the project's default locale.
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
const defaultLocale = verba.getDefaultLocale() // 'en'
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### `verba.ready()`
|
|
131
|
+
|
|
132
|
+
Wait for translations to be loaded. Useful if you need to ensure translations are available before rendering.
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
await verba.ready()
|
|
136
|
+
// Translations are now loaded
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## How It Works
|
|
140
|
+
|
|
141
|
+
1. **Initialization**: When you create a `Verba` instance, it immediately fetches all translations from the API.
|
|
142
|
+
|
|
143
|
+
2. **Caching**: Translations are cached in memory. The SDK uses ETags for efficient cache validation.
|
|
144
|
+
|
|
145
|
+
3. **Synchronous Access**: After initialization, `t()` calls are synchronous and instant.
|
|
146
|
+
|
|
147
|
+
4. **Auto-creation**: Missing keys with default values are created in the background without blocking your app.
|
|
148
|
+
|
|
149
|
+
## Framework Examples
|
|
150
|
+
|
|
151
|
+
### React
|
|
152
|
+
|
|
153
|
+
```tsx
|
|
154
|
+
import { Verba } from '@verbadev/js'
|
|
155
|
+
import { createContext, useContext, useState, useEffect } from 'react'
|
|
156
|
+
|
|
157
|
+
const verba = new Verba({
|
|
158
|
+
projectId: 'your-project-id',
|
|
159
|
+
publicKey: 'pk_your-public-key',
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
const VerbaContext = createContext(verba)
|
|
163
|
+
|
|
164
|
+
export function VerbaProvider({ children }: { children: React.ReactNode }) {
|
|
165
|
+
const [, forceUpdate] = useState(0)
|
|
166
|
+
|
|
167
|
+
useEffect(() => {
|
|
168
|
+
verba.ready().then(() => forceUpdate(1))
|
|
169
|
+
}, [])
|
|
170
|
+
|
|
171
|
+
return (
|
|
172
|
+
<VerbaContext.Provider value={verba}>
|
|
173
|
+
{children}
|
|
174
|
+
</VerbaContext.Provider>
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function useTranslation() {
|
|
179
|
+
const verba = useContext(VerbaContext)
|
|
180
|
+
return {
|
|
181
|
+
t: verba.t.bind(verba),
|
|
182
|
+
setLocale: (locale: string) => verba.setLocale(locale),
|
|
183
|
+
locale: verba.getLocale(),
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Usage:
|
|
188
|
+
// const { t } = useTranslation()
|
|
189
|
+
// t('greeting', 'Hello, {name}!', { name: 'World' })
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Next.js (App Router)
|
|
193
|
+
|
|
194
|
+
```tsx
|
|
195
|
+
// lib/verba.ts
|
|
196
|
+
import { Verba } from '@verbadev/js'
|
|
197
|
+
|
|
198
|
+
export const verba = new Verba({
|
|
199
|
+
projectId: 'your-project-id',
|
|
200
|
+
publicKey: 'pk_your-public-key',
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
// components/LocaleSwitcher.tsx
|
|
204
|
+
'use client'
|
|
205
|
+
import { verba } from '@/lib/verba'
|
|
206
|
+
|
|
207
|
+
export function LocaleSwitcher() {
|
|
208
|
+
return (
|
|
209
|
+
<select onChange={(e) => verba.setLocale(e.target.value)}>
|
|
210
|
+
{verba.getLocales().map((locale) => (
|
|
211
|
+
<option key={locale} value={locale}>{locale}</option>
|
|
212
|
+
))}
|
|
213
|
+
</select>
|
|
214
|
+
)
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Vue
|
|
219
|
+
|
|
220
|
+
```vue
|
|
221
|
+
<script setup>
|
|
222
|
+
import { Verba } from '@verbadev/js'
|
|
223
|
+
import { ref, onMounted } from 'vue'
|
|
224
|
+
|
|
225
|
+
const verba = new Verba({
|
|
226
|
+
projectId: 'your-project-id',
|
|
227
|
+
publicKey: 'pk_your-public-key',
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
const ready = ref(false)
|
|
231
|
+
|
|
232
|
+
onMounted(async () => {
|
|
233
|
+
await verba.ready()
|
|
234
|
+
ready.value = true
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
const t = (key, defaultValue) => verba.t(key, defaultValue)
|
|
238
|
+
</script>
|
|
239
|
+
|
|
240
|
+
<template>
|
|
241
|
+
<div v-if="ready">
|
|
242
|
+
<h1>{{ t('welcome.title', 'Welcome!') }}</h1>
|
|
243
|
+
</div>
|
|
244
|
+
</template>
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## TypeScript
|
|
248
|
+
|
|
249
|
+
The SDK is written in TypeScript and includes full type definitions.
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
import { Verba, VerbaConfig } from '@verbadev/js'
|
|
253
|
+
|
|
254
|
+
const config: VerbaConfig = {
|
|
255
|
+
projectId: 'your-project-id',
|
|
256
|
+
publicKey: 'pk_your-public-key',
|
|
257
|
+
locale: 'en',
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const verba = new Verba(config)
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## License
|
|
264
|
+
|
|
265
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
interface VerbaConfig {
|
|
2
|
+
projectId: string;
|
|
3
|
+
publicKey: string;
|
|
4
|
+
/**
|
|
5
|
+
* Locale to use.
|
|
6
|
+
* - If omitted or 'auto': auto-detects from browser (navigator.language)
|
|
7
|
+
* - If specified: uses the exact locale provided
|
|
8
|
+
*/
|
|
9
|
+
locale?: string | 'auto';
|
|
10
|
+
baseUrl?: string;
|
|
11
|
+
}
|
|
12
|
+
interface TranslationsResponse {
|
|
13
|
+
version: number;
|
|
14
|
+
defaultLocale: string;
|
|
15
|
+
locales: string[];
|
|
16
|
+
translations: Record<string, Record<string, string>>;
|
|
17
|
+
}
|
|
18
|
+
interface CreateKeyResponse {
|
|
19
|
+
created: boolean;
|
|
20
|
+
key: string;
|
|
21
|
+
translations: Record<string, string>;
|
|
22
|
+
}
|
|
23
|
+
interface CachedTranslations {
|
|
24
|
+
version: number;
|
|
25
|
+
defaultLocale: string;
|
|
26
|
+
locales: string[];
|
|
27
|
+
data: Record<string, Record<string, string>>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
declare class Verba {
|
|
31
|
+
private projectId;
|
|
32
|
+
private publicKey;
|
|
33
|
+
private baseUrl;
|
|
34
|
+
private locale;
|
|
35
|
+
private autoDetect;
|
|
36
|
+
private cache;
|
|
37
|
+
private fetchPromise;
|
|
38
|
+
private pendingKeys;
|
|
39
|
+
constructor(config: VerbaConfig);
|
|
40
|
+
/**
|
|
41
|
+
* Set the current locale.
|
|
42
|
+
*/
|
|
43
|
+
setLocale(locale: string): void;
|
|
44
|
+
/**
|
|
45
|
+
* Get the current locale.
|
|
46
|
+
*/
|
|
47
|
+
getLocale(): string;
|
|
48
|
+
/**
|
|
49
|
+
* Get list of available locales.
|
|
50
|
+
*/
|
|
51
|
+
getLocales(): string[];
|
|
52
|
+
/**
|
|
53
|
+
* Get the default locale.
|
|
54
|
+
*/
|
|
55
|
+
getDefaultLocale(): string | null;
|
|
56
|
+
/**
|
|
57
|
+
* Get a translation for a key.
|
|
58
|
+
*
|
|
59
|
+
* @param key - The translation key
|
|
60
|
+
* @param defaultValueOrParams - Either a default value string, or params object for interpolation
|
|
61
|
+
* @param params - Params object for interpolation (when defaultValue is also provided)
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* verba.t('greeting') // just key
|
|
65
|
+
* verba.t('greeting', 'Hello!') // with fallback
|
|
66
|
+
* verba.t('greeting', { name: 'World' }) // with params
|
|
67
|
+
* verba.t('greeting', 'Hello, {name}!', { name: 'World' }) // both
|
|
68
|
+
*/
|
|
69
|
+
t(key: string, defaultValueOrParams?: string | Record<string, string | number>, params?: Record<string, string | number>): string;
|
|
70
|
+
/**
|
|
71
|
+
* Interpolate params into a string.
|
|
72
|
+
* Replaces {key} with the corresponding value from params.
|
|
73
|
+
*/
|
|
74
|
+
private interpolate;
|
|
75
|
+
/**
|
|
76
|
+
* Wait for translations to be loaded.
|
|
77
|
+
* Call this if you need to ensure translations are ready.
|
|
78
|
+
*/
|
|
79
|
+
ready(): Promise<void>;
|
|
80
|
+
private fetchTranslations;
|
|
81
|
+
private createKeyInBackground;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export { type CachedTranslations, type CreateKeyResponse, type TranslationsResponse, Verba, type VerbaConfig };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
interface VerbaConfig {
|
|
2
|
+
projectId: string;
|
|
3
|
+
publicKey: string;
|
|
4
|
+
/**
|
|
5
|
+
* Locale to use.
|
|
6
|
+
* - If omitted or 'auto': auto-detects from browser (navigator.language)
|
|
7
|
+
* - If specified: uses the exact locale provided
|
|
8
|
+
*/
|
|
9
|
+
locale?: string | 'auto';
|
|
10
|
+
baseUrl?: string;
|
|
11
|
+
}
|
|
12
|
+
interface TranslationsResponse {
|
|
13
|
+
version: number;
|
|
14
|
+
defaultLocale: string;
|
|
15
|
+
locales: string[];
|
|
16
|
+
translations: Record<string, Record<string, string>>;
|
|
17
|
+
}
|
|
18
|
+
interface CreateKeyResponse {
|
|
19
|
+
created: boolean;
|
|
20
|
+
key: string;
|
|
21
|
+
translations: Record<string, string>;
|
|
22
|
+
}
|
|
23
|
+
interface CachedTranslations {
|
|
24
|
+
version: number;
|
|
25
|
+
defaultLocale: string;
|
|
26
|
+
locales: string[];
|
|
27
|
+
data: Record<string, Record<string, string>>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
declare class Verba {
|
|
31
|
+
private projectId;
|
|
32
|
+
private publicKey;
|
|
33
|
+
private baseUrl;
|
|
34
|
+
private locale;
|
|
35
|
+
private autoDetect;
|
|
36
|
+
private cache;
|
|
37
|
+
private fetchPromise;
|
|
38
|
+
private pendingKeys;
|
|
39
|
+
constructor(config: VerbaConfig);
|
|
40
|
+
/**
|
|
41
|
+
* Set the current locale.
|
|
42
|
+
*/
|
|
43
|
+
setLocale(locale: string): void;
|
|
44
|
+
/**
|
|
45
|
+
* Get the current locale.
|
|
46
|
+
*/
|
|
47
|
+
getLocale(): string;
|
|
48
|
+
/**
|
|
49
|
+
* Get list of available locales.
|
|
50
|
+
*/
|
|
51
|
+
getLocales(): string[];
|
|
52
|
+
/**
|
|
53
|
+
* Get the default locale.
|
|
54
|
+
*/
|
|
55
|
+
getDefaultLocale(): string | null;
|
|
56
|
+
/**
|
|
57
|
+
* Get a translation for a key.
|
|
58
|
+
*
|
|
59
|
+
* @param key - The translation key
|
|
60
|
+
* @param defaultValueOrParams - Either a default value string, or params object for interpolation
|
|
61
|
+
* @param params - Params object for interpolation (when defaultValue is also provided)
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* verba.t('greeting') // just key
|
|
65
|
+
* verba.t('greeting', 'Hello!') // with fallback
|
|
66
|
+
* verba.t('greeting', { name: 'World' }) // with params
|
|
67
|
+
* verba.t('greeting', 'Hello, {name}!', { name: 'World' }) // both
|
|
68
|
+
*/
|
|
69
|
+
t(key: string, defaultValueOrParams?: string | Record<string, string | number>, params?: Record<string, string | number>): string;
|
|
70
|
+
/**
|
|
71
|
+
* Interpolate params into a string.
|
|
72
|
+
* Replaces {key} with the corresponding value from params.
|
|
73
|
+
*/
|
|
74
|
+
private interpolate;
|
|
75
|
+
/**
|
|
76
|
+
* Wait for translations to be loaded.
|
|
77
|
+
* Call this if you need to ensure translations are ready.
|
|
78
|
+
*/
|
|
79
|
+
ready(): Promise<void>;
|
|
80
|
+
private fetchTranslations;
|
|
81
|
+
private createKeyInBackground;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export { type CachedTranslations, type CreateKeyResponse, type TranslationsResponse, Verba, type VerbaConfig };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var l=Object.defineProperty;var h=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var d=Object.prototype.hasOwnProperty;var g=(n,e)=>{for(var s in e)l(n,s,{get:e[s],enumerable:!0})},p=(n,e,s,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of u(e))!d.call(n,t)&&t!==s&&l(n,t,{get:()=>e[t],enumerable:!(r=h(e,t))||r.enumerable});return n};var f=n=>p(l({},"__esModule",{value:!0}),n);var m={};g(m,{Verba:()=>o});module.exports=f(m);var y="https://verba.dev";function b(){return typeof navigator>"u"?null:(navigator.languages??[navigator.language])[0]??null}function v(n,e){if(e.includes(n))return n;let s=n.split("-")[0];if(e.includes(s))return s;let r=e.find(t=>t.startsWith(s+"-"));return r||null}var o=class{constructor(e){this.cache=null;this.fetchPromise=null;this.pendingKeys=new Set;this.projectId=e.projectId,this.publicKey=e.publicKey,this.baseUrl=e.baseUrl??y,this.autoDetect=e.locale===void 0||e.locale==="auto",this.autoDetect?this.locale=b()??"en":this.locale=e.locale,this.fetchPromise=this.fetchTranslations()}setLocale(e){this.locale=e}getLocale(){return this.locale}getLocales(){return this.cache?.locales??[]}getDefaultLocale(){return this.cache?.defaultLocale??null}t(e,s,r){let t,i;typeof s=="string"?(t=s,i=r):typeof s=="object"&&(i=s);let a;if(!this.cache)t!==void 0&&this.createKeyInBackground(e,t),a=t??e;else{let c=this.cache.data[e];c?a=c[this.locale]??c[this.cache.defaultLocale]??t??e:(t!==void 0&&this.createKeyInBackground(e,t),a=t??e)}return i&&(a=this.interpolate(a,i)),a}interpolate(e,s){return e.replace(/\{(\w+)\}/g,(r,t)=>s[t]!==void 0?String(s[t]):r)}async ready(){this.fetchPromise&&await this.fetchPromise}async fetchTranslations(){let e=`${this.baseUrl}/api/sdk/${this.projectId}/translations`,s={"X-Public-Key":this.publicKey};this.cache&&(s["If-None-Match"]=String(this.cache.version));try{let r=await fetch(e,{headers:s});if(r.status===304&&this.cache)return this.cache;if(!r.ok)throw new Error(`Failed to fetch translations: ${r.status}`);let t=await r.json();if(this.cache={version:t.version,defaultLocale:t.defaultLocale,locales:t.locales,data:t.translations},this.autoDetect){let i=v(this.locale,t.locales);this.locale=i??t.defaultLocale}return this.cache}catch(r){throw console.error("[Verba] Failed to fetch translations:",r),r}}async createKeyInBackground(e,s){if(!this.pendingKeys.has(e)){this.pendingKeys.add(e);try{let r=`${this.baseUrl}/api/sdk/${this.projectId}/keys`,t=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json","X-Public-Key":this.publicKey},body:JSON.stringify({key:e,defaultValue:s})});if(!t.ok){let a=await t.json().catch(()=>({}));console.error("[Verba] Failed to create key:",a.error??t.status);return}let i=await t.json();this.cache&&i.translations&&(this.cache.data[e]=i.translations)}catch(r){console.error("[Verba] Failed to create key:",r)}finally{this.pendingKeys.delete(e)}}}};0&&(module.exports={Verba});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var l="https://verba.dev";function h(){return typeof navigator>"u"?null:(navigator.languages??[navigator.language])[0]??null}function u(a,e){if(e.includes(a))return a;let r=a.split("-")[0];if(e.includes(r))return r;let s=e.find(t=>t.startsWith(r+"-"));return s||null}var c=class{constructor(e){this.cache=null;this.fetchPromise=null;this.pendingKeys=new Set;this.projectId=e.projectId,this.publicKey=e.publicKey,this.baseUrl=e.baseUrl??l,this.autoDetect=e.locale===void 0||e.locale==="auto",this.autoDetect?this.locale=h()??"en":this.locale=e.locale,this.fetchPromise=this.fetchTranslations()}setLocale(e){this.locale=e}getLocale(){return this.locale}getLocales(){return this.cache?.locales??[]}getDefaultLocale(){return this.cache?.defaultLocale??null}t(e,r,s){let t,n;typeof r=="string"?(t=r,n=s):typeof r=="object"&&(n=r);let i;if(!this.cache)t!==void 0&&this.createKeyInBackground(e,t),i=t??e;else{let o=this.cache.data[e];o?i=o[this.locale]??o[this.cache.defaultLocale]??t??e:(t!==void 0&&this.createKeyInBackground(e,t),i=t??e)}return n&&(i=this.interpolate(i,n)),i}interpolate(e,r){return e.replace(/\{(\w+)\}/g,(s,t)=>r[t]!==void 0?String(r[t]):s)}async ready(){this.fetchPromise&&await this.fetchPromise}async fetchTranslations(){let e=`${this.baseUrl}/api/sdk/${this.projectId}/translations`,r={"X-Public-Key":this.publicKey};this.cache&&(r["If-None-Match"]=String(this.cache.version));try{let s=await fetch(e,{headers:r});if(s.status===304&&this.cache)return this.cache;if(!s.ok)throw new Error(`Failed to fetch translations: ${s.status}`);let t=await s.json();if(this.cache={version:t.version,defaultLocale:t.defaultLocale,locales:t.locales,data:t.translations},this.autoDetect){let n=u(this.locale,t.locales);this.locale=n??t.defaultLocale}return this.cache}catch(s){throw console.error("[Verba] Failed to fetch translations:",s),s}}async createKeyInBackground(e,r){if(!this.pendingKeys.has(e)){this.pendingKeys.add(e);try{let s=`${this.baseUrl}/api/sdk/${this.projectId}/keys`,t=await fetch(s,{method:"POST",headers:{"Content-Type":"application/json","X-Public-Key":this.publicKey},body:JSON.stringify({key:e,defaultValue:r})});if(!t.ok){let i=await t.json().catch(()=>({}));console.error("[Verba] Failed to create key:",i.error??t.status);return}let n=await t.json();this.cache&&n.translations&&(this.cache.data[e]=n.translations)}catch(s){console.error("[Verba] Failed to create key:",s)}finally{this.pendingKeys.delete(e)}}}};export{c as Verba};
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@verbadev/js",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "JavaScript SDK for Verba Translation Management System",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsup",
|
|
20
|
+
"dev": "tsup --watch",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"prepublishOnly": "npm run build"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"verba",
|
|
26
|
+
"translations",
|
|
27
|
+
"i18n",
|
|
28
|
+
"localization",
|
|
29
|
+
"l10n"
|
|
30
|
+
],
|
|
31
|
+
"author": "",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"tsup": "^8.0.0",
|
|
35
|
+
"tsx": "^4.21.0",
|
|
36
|
+
"typescript": "^5.0.0"
|
|
37
|
+
},
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": ""
|
|
41
|
+
}
|
|
42
|
+
}
|