@kokimoki/app 2.1.0 → 3.0.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 +72 -0
- package/dist/core/kokimoki-client.d.ts +75 -15
- package/dist/core/kokimoki-client.js +137 -22
- package/dist/index.d.ts +6 -1
- package/dist/index.js +4 -0
- package/dist/kokimoki.min.d.ts +322 -2
- package/dist/kokimoki.min.js +1884 -72
- package/dist/kokimoki.min.js.map +1 -1
- package/dist/llms.txt +6 -0
- package/dist/protocol/ws-message/reader.d.ts +1 -1
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +1 -0
- package/dist/services/kokimoki-ai.d.ts +185 -122
- package/dist/services/kokimoki-ai.js +201 -109
- package/dist/services/kokimoki-i18n.d.ts +259 -0
- package/dist/services/kokimoki-i18n.js +325 -0
- package/dist/stores/kokimoki-local-store.d.ts +1 -1
- package/dist/types/common.d.ts +9 -0
- package/dist/types/env.d.ts +36 -0
- package/dist/types/env.js +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/utils/kokimoki-client.d.ts +31 -0
- package/dist/utils/kokimoki-client.js +38 -0
- package/dist/utils/kokimoki-dev.d.ts +30 -0
- package/dist/utils/kokimoki-dev.js +75 -0
- package/dist/utils/kokimoki-env.d.ts +20 -0
- package/dist/utils/kokimoki-env.js +30 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/kokimoki-ai.instructions.md +316 -0
- package/docs/kokimoki-dynamic-stores.instructions.md +439 -0
- package/docs/kokimoki-i18n.instructions.md +285 -0
- package/docs/kokimoki-leaderboard.instructions.md +189 -0
- package/docs/kokimoki-sdk.instructions.md +221 -0
- package/docs/kokimoki-storage.instructions.md +162 -0
- package/llms.txt +43 -0
- package/package.json +9 -13
|
@@ -1,15 +1,18 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
1
2
|
/**
|
|
2
3
|
* Kokimoki AI Integration Service
|
|
3
4
|
*
|
|
4
5
|
* Provides built-in AI capabilities for game applications without requiring API keys or setup.
|
|
5
|
-
*
|
|
6
|
+
* All generation methods are async job-based - they submit a job and return immediately with a jobId.
|
|
7
|
+
* Use the corresponding poll method to wait for the result.
|
|
6
8
|
*
|
|
7
9
|
* **Key Features:**
|
|
8
10
|
* - Multiple AI models (GPT-4, GPT-5, Gemini variants)
|
|
9
11
|
* - Text generation with configurable creativity (temperature)
|
|
10
|
-
* - Structured JSON output
|
|
11
|
-
* - AI-powered image
|
|
12
|
-
* -
|
|
12
|
+
* - Structured JSON output with Zod schema validation
|
|
13
|
+
* - AI-powered image generation and modification
|
|
14
|
+
* - Job-based async processing with polling support
|
|
15
|
+
* - Resumable after page reload (persist jobId)
|
|
13
16
|
*
|
|
14
17
|
* **Common Use Cases:**
|
|
15
18
|
* - Generate dynamic game content (quests, dialogues, stories)
|
|
@@ -23,28 +26,24 @@
|
|
|
23
26
|
*
|
|
24
27
|
* @example
|
|
25
28
|
* ```typescript
|
|
26
|
-
* // Generate
|
|
27
|
-
* const
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
29
|
+
* // Generate structured game data
|
|
30
|
+
* const enemySchema = z.object({
|
|
31
|
+
* name: z.string(),
|
|
32
|
+
* health: z.number(),
|
|
33
|
+
* attack: z.number()
|
|
31
34
|
* });
|
|
32
35
|
*
|
|
33
|
-
* //
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* attack: number;
|
|
38
|
-
* }
|
|
39
|
-
* const enemy = await kmClient.ai.generateJson<Enemy>({
|
|
40
|
-
* userPrompt: 'Create a level 5 goblin warrior'
|
|
36
|
+
* // Submit job
|
|
37
|
+
* const { jobId } = await kmClient.ai.generateJson({
|
|
38
|
+
* schema: enemySchema,
|
|
39
|
+
* prompt: 'Create a level 5 goblin warrior'
|
|
41
40
|
* });
|
|
42
41
|
*
|
|
43
|
-
* //
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* );
|
|
42
|
+
* // Save jobId to store for persistence across reloads
|
|
43
|
+
* await saveJobId(jobId);
|
|
44
|
+
*
|
|
45
|
+
* // Poll for result (can resume after reload)
|
|
46
|
+
* const enemy = await kmClient.ai.pollJson(jobId, { schema: enemySchema });
|
|
48
47
|
* ```
|
|
49
48
|
*/
|
|
50
49
|
export class KokimokiAiService {
|
|
@@ -52,56 +51,37 @@ export class KokimokiAiService {
|
|
|
52
51
|
constructor(client) {
|
|
53
52
|
this.client = client;
|
|
54
53
|
}
|
|
54
|
+
// ============================================================
|
|
55
|
+
// Job Submission Methods
|
|
56
|
+
// ============================================================
|
|
55
57
|
/**
|
|
56
|
-
* Generate
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* @
|
|
63
|
-
* @param req.model Optional. The AI model to use. Defaults to server-side default if not specified.
|
|
64
|
-
* Available models:
|
|
65
|
-
* - `gpt-4o`: OpenAI GPT-4 Optimized
|
|
66
|
-
* - `gpt-4o-mini`: Smaller, faster GPT-4 variant
|
|
67
|
-
* - `gpt-5`: OpenAI GPT-5 (latest)
|
|
68
|
-
* - `gpt-5-mini`: Smaller GPT-5 variant
|
|
69
|
-
* - `gpt-5-nano`: Smallest GPT-5 variant for lightweight tasks
|
|
70
|
-
* - `gemini-2.5-flash-lite`: Google Gemini lite variant
|
|
71
|
-
* - `gemini-2.5-flash`: Google Gemini fast variant
|
|
72
|
-
* - `gemini-3-flash-preview`: Google Gemini 3 Flash preview
|
|
73
|
-
* - `gemini-3-pro-preview`: Google Gemini 3 Pro preview
|
|
74
|
-
* @param req.systemPrompt Optional. The system message that sets the behavior and context for the AI.
|
|
75
|
-
* This helps define the AI's role, personality, and constraints.
|
|
76
|
-
* @param req.userPrompt The user's message or question to send to the AI.
|
|
77
|
-
* @param req.temperature Optional. Controls randomness in the response (0.0 to 1.0).
|
|
78
|
-
* Lower values make output more focused and deterministic,
|
|
79
|
-
* higher values make it more creative and varied.
|
|
80
|
-
* @param req.maxTokens Optional. The maximum number of tokens to generate in the response.
|
|
81
|
-
* Controls the length of the AI's output.
|
|
82
|
-
*
|
|
83
|
-
* @returns A promise that resolves to an object containing the AI-generated response.
|
|
84
|
-
* @returns {string} content The text content of the AI's response.
|
|
85
|
-
*
|
|
86
|
-
* @throws An error object if the API request fails.
|
|
58
|
+
* Generate text content from the AI model.
|
|
59
|
+
*
|
|
60
|
+
* Submits a text generation job and returns immediately with a jobId.
|
|
61
|
+
* Use `pollText()` to wait for the result.
|
|
62
|
+
*
|
|
63
|
+
* @param req The generation request parameters.
|
|
64
|
+
* @returns A promise that resolves to an object containing the jobId.
|
|
87
65
|
*
|
|
88
66
|
* @example
|
|
89
67
|
* ```typescript
|
|
90
|
-
* const
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
* temperature: 0.7,
|
|
95
|
-
* maxTokens: 100
|
|
68
|
+
* const { jobId } = await kmClient.ai.generateText({
|
|
69
|
+
* systemPrompt: 'You are a fantasy story writer',
|
|
70
|
+
* prompt: 'Write a short quest description',
|
|
71
|
+
* temperature: 0.8
|
|
96
72
|
* });
|
|
97
|
-
*
|
|
73
|
+
*
|
|
74
|
+
* const text = await kmClient.ai.pollText(jobId);
|
|
98
75
|
* ```
|
|
99
76
|
*/
|
|
100
|
-
async
|
|
101
|
-
const res = await fetch(`${this.client.apiUrl}/ai/
|
|
77
|
+
async generateText(req) {
|
|
78
|
+
const res = await fetch(`${this.client.apiUrl}/ai/jobs`, {
|
|
102
79
|
method: "POST",
|
|
103
80
|
headers: this.client.apiHeaders,
|
|
104
|
-
body: JSON.stringify(
|
|
81
|
+
body: JSON.stringify({
|
|
82
|
+
type: "text",
|
|
83
|
+
...req,
|
|
84
|
+
}),
|
|
105
85
|
});
|
|
106
86
|
if (!res.ok) {
|
|
107
87
|
throw await res.json();
|
|
@@ -111,64 +91,176 @@ export class KokimokiAiService {
|
|
|
111
91
|
/**
|
|
112
92
|
* Generate structured JSON output from the AI model.
|
|
113
93
|
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
* @param req.temperature Optional. Controls randomness in the response (0.0 to 1.0).
|
|
138
|
-
* Lower values make output more focused and deterministic,
|
|
139
|
-
* higher values make it more creative and varied.
|
|
140
|
-
* @param req.maxTokens Optional. The maximum number of tokens to generate in the response.
|
|
141
|
-
* Controls the length of the AI's output.
|
|
142
|
-
* @param req.imageUrls Optional. Image URLs to include with the user prompt (Gemini models only).
|
|
143
|
-
* Allows the AI to analyze images and generate structured JSON based on them.
|
|
144
|
-
*
|
|
145
|
-
* @returns A promise that resolves to the parsed JSON object generated by the AI.
|
|
146
|
-
*
|
|
147
|
-
* @throws An error object if the API request fails or if the response is not valid JSON.
|
|
94
|
+
* Submits a JSON generation job and returns immediately with a jobId.
|
|
95
|
+
* The Zod schema is converted to JSON Schema and sent to the AI.
|
|
96
|
+
* Use `pollJson()` to wait for the result with type inference.
|
|
97
|
+
*
|
|
98
|
+
* @param req The generation request parameters including Zod schema.
|
|
99
|
+
* @returns A promise that resolves to an object containing the jobId.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```typescript
|
|
103
|
+
* const enemySchema = z.object({
|
|
104
|
+
* name: z.string(),
|
|
105
|
+
* health: z.number(),
|
|
106
|
+
* attack: z.number()
|
|
107
|
+
* });
|
|
108
|
+
*
|
|
109
|
+
* const { jobId } = await kmClient.ai.generateJson({
|
|
110
|
+
* schema: enemySchema,
|
|
111
|
+
* prompt: 'Create a level 5 goblin warrior'
|
|
112
|
+
* });
|
|
113
|
+
*
|
|
114
|
+
* // Poll with schema for type inference and validation
|
|
115
|
+
* const enemy = await kmClient.ai.pollJson(jobId, { schema: enemySchema });
|
|
116
|
+
* ```
|
|
148
117
|
*/
|
|
149
118
|
async generateJson(req) {
|
|
150
|
-
const {
|
|
151
|
-
|
|
152
|
-
|
|
119
|
+
const { schema, ...rest } = req;
|
|
120
|
+
const jsonSchema = z.toJSONSchema(schema);
|
|
121
|
+
const res = await fetch(`${this.client.apiUrl}/ai/jobs`, {
|
|
122
|
+
method: "POST",
|
|
123
|
+
headers: this.client.apiHeaders,
|
|
124
|
+
body: JSON.stringify({
|
|
125
|
+
type: "json",
|
|
126
|
+
jsonSchema,
|
|
127
|
+
...rest,
|
|
128
|
+
}),
|
|
153
129
|
});
|
|
154
|
-
|
|
130
|
+
if (!res.ok) {
|
|
131
|
+
throw await res.json();
|
|
132
|
+
}
|
|
133
|
+
return await res.json();
|
|
155
134
|
}
|
|
156
135
|
/**
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
136
|
+
* Generate or modify an image using the AI model.
|
|
137
|
+
*
|
|
138
|
+
* Submits an image generation job and returns immediately with a jobId.
|
|
139
|
+
* Use `pollImage()` to wait for the result.
|
|
140
|
+
*
|
|
141
|
+
* @param req The generation request parameters.
|
|
142
|
+
* @returns A promise that resolves to an object containing the jobId.
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```typescript
|
|
146
|
+
* // Modify existing image
|
|
147
|
+
* const { jobId } = await kmClient.ai.generateImage({
|
|
148
|
+
* imageUrls: [imageUrl],
|
|
149
|
+
* prompt: 'Make it look like pixel art'
|
|
150
|
+
* });
|
|
151
|
+
*
|
|
152
|
+
* const image = await kmClient.ai.pollImage(jobId);
|
|
153
|
+
* ```
|
|
162
154
|
*/
|
|
163
|
-
async
|
|
164
|
-
const res = await fetch(`${this.client.apiUrl}/ai/
|
|
155
|
+
async generateImage(req) {
|
|
156
|
+
const res = await fetch(`${this.client.apiUrl}/ai/jobs`, {
|
|
165
157
|
method: "POST",
|
|
166
158
|
headers: this.client.apiHeaders,
|
|
167
|
-
body: JSON.stringify({
|
|
159
|
+
body: JSON.stringify({
|
|
160
|
+
type: "image",
|
|
161
|
+
model: req.model ?? "gemini-2.5-flash-image",
|
|
162
|
+
prompt: req.prompt,
|
|
163
|
+
imageUrls: req.imageUrls,
|
|
164
|
+
tags: req.tags ?? [],
|
|
165
|
+
}),
|
|
168
166
|
});
|
|
169
167
|
if (!res.ok) {
|
|
170
168
|
throw await res.json();
|
|
171
169
|
}
|
|
172
170
|
return await res.json();
|
|
173
171
|
}
|
|
172
|
+
// ============================================================
|
|
173
|
+
// Job Status & Polling Methods
|
|
174
|
+
// ============================================================
|
|
175
|
+
/**
|
|
176
|
+
* Get the current status of an AI job.
|
|
177
|
+
*
|
|
178
|
+
* One-shot status check without polling.
|
|
179
|
+
*
|
|
180
|
+
* @param jobId The job ID to check.
|
|
181
|
+
* @returns A promise that resolves to the job information.
|
|
182
|
+
*/
|
|
183
|
+
async getJob(jobId) {
|
|
184
|
+
const res = await fetch(`${this.client.apiUrl}/ai/jobs/${jobId}`, {
|
|
185
|
+
method: "GET",
|
|
186
|
+
headers: this.client.apiHeaders,
|
|
187
|
+
});
|
|
188
|
+
if (!res.ok) {
|
|
189
|
+
throw await res.json();
|
|
190
|
+
}
|
|
191
|
+
return await res.json();
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Poll a text generation job until completion.
|
|
195
|
+
*
|
|
196
|
+
* @param jobId The job ID to poll.
|
|
197
|
+
* @param options Polling options (interval, timeout, progress callback).
|
|
198
|
+
* @returns A promise that resolves to the generated text.
|
|
199
|
+
* @throws If the job fails or times out.
|
|
200
|
+
*/
|
|
201
|
+
async pollText(jobId, options) {
|
|
202
|
+
const result = await this.pollJob(jobId, options);
|
|
203
|
+
return result;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Poll a JSON generation job until completion.
|
|
207
|
+
*
|
|
208
|
+
* @param jobId The job ID to poll.
|
|
209
|
+
* @param options Polling options including the Zod schema for validation.
|
|
210
|
+
* @returns A promise that resolves to the parsed and validated JSON.
|
|
211
|
+
* @throws If the job fails, times out, or validation fails.
|
|
212
|
+
*
|
|
213
|
+
* @example
|
|
214
|
+
* ```typescript
|
|
215
|
+
* const enemy = await kmClient.ai.pollJson(savedJobId, {
|
|
216
|
+
* schema: enemySchema,
|
|
217
|
+
* timeout: 60000,
|
|
218
|
+
* onProgress: (status) => console.log('Status:', status)
|
|
219
|
+
* });
|
|
220
|
+
* ```
|
|
221
|
+
*/
|
|
222
|
+
async pollJson(jobId, options) {
|
|
223
|
+
const { schema, ...pollOptions } = options;
|
|
224
|
+
const result = await this.pollJob(jobId, pollOptions);
|
|
225
|
+
return schema.parse(result);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Poll an image generation job until completion.
|
|
229
|
+
*
|
|
230
|
+
* @param jobId The job ID to poll.
|
|
231
|
+
* @param options Polling options (interval, timeout, progress callback).
|
|
232
|
+
* @returns A promise that resolves to the upload information.
|
|
233
|
+
* @throws If the job fails or times out.
|
|
234
|
+
*/
|
|
235
|
+
async pollImage(jobId, options) {
|
|
236
|
+
const result = await this.pollJob(jobId, options);
|
|
237
|
+
return result;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Internal polling implementation.
|
|
241
|
+
*/
|
|
242
|
+
async pollJob(jobId, options) {
|
|
243
|
+
const pollInterval = Math.max(1000, options?.pollInterval ?? 2000);
|
|
244
|
+
const timeout = options?.timeout ?? 120000;
|
|
245
|
+
const startTime = Date.now();
|
|
246
|
+
while (true) {
|
|
247
|
+
const job = await this.getJob(jobId);
|
|
248
|
+
// Call progress callback
|
|
249
|
+
options?.onProgress?.(job.status);
|
|
250
|
+
if (job.status === "completed") {
|
|
251
|
+
return job.result;
|
|
252
|
+
}
|
|
253
|
+
if (job.status === "failed") {
|
|
254
|
+
throw new Error(job.error?.message ?? "AI job failed");
|
|
255
|
+
}
|
|
256
|
+
// processing and queued both continue polling
|
|
257
|
+
// queued jobs will be promoted when slots become available
|
|
258
|
+
// Check timeout
|
|
259
|
+
if (Date.now() - startTime > timeout) {
|
|
260
|
+
throw new Error(`AI job timed out after ${timeout}ms`);
|
|
261
|
+
}
|
|
262
|
+
// Wait before next poll
|
|
263
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
264
|
+
}
|
|
265
|
+
}
|
|
174
266
|
}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import i18next, { type i18n } from "i18next";
|
|
2
|
+
import type { KokimokiClient } from "../core";
|
|
3
|
+
import type { PollOptions } from "../types";
|
|
4
|
+
/**
|
|
5
|
+
* Options for creating an i18n instance.
|
|
6
|
+
*/
|
|
7
|
+
export interface I18nOptions {
|
|
8
|
+
/** Fallback language code (default: same as lng passed to init) */
|
|
9
|
+
fallbackLng?: string;
|
|
10
|
+
/** Default namespace (default: first namespace in the list) */
|
|
11
|
+
defaultNS?: string;
|
|
12
|
+
/** Array of i18next plugins to use (e.g., initReactI18next) */
|
|
13
|
+
use?: Parameters<typeof i18next.use>[0][];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Status of a single namespace translation.
|
|
17
|
+
*/
|
|
18
|
+
export type NamespaceStatus = "available" | "processing" | "failed" | "not_available";
|
|
19
|
+
/**
|
|
20
|
+
* Aggregated status of a language across all namespaces.
|
|
21
|
+
*/
|
|
22
|
+
export type LanguageStatus = "available" | "processing" | "failed" | "partial";
|
|
23
|
+
/**
|
|
24
|
+
* Translation status for a specific language.
|
|
25
|
+
*/
|
|
26
|
+
export interface TranslationStatus {
|
|
27
|
+
/** Overall status of the language */
|
|
28
|
+
status: "available" | "processing" | "not_available";
|
|
29
|
+
/** Status per namespace */
|
|
30
|
+
namespaces: Record<string, NamespaceStatus>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Status of all languages that have been requested.
|
|
34
|
+
*/
|
|
35
|
+
export interface AllLanguagesStatus {
|
|
36
|
+
/** Array of language statuses */
|
|
37
|
+
languages: {
|
|
38
|
+
lng: string;
|
|
39
|
+
status: LanguageStatus;
|
|
40
|
+
}[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Result of requesting a translation.
|
|
44
|
+
*/
|
|
45
|
+
export interface RequestTranslationResult {
|
|
46
|
+
/** Language code that was requested */
|
|
47
|
+
lng: string;
|
|
48
|
+
/** Status of the request */
|
|
49
|
+
status: "started" | "already_processing" | "already_available";
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Kokimoki i18n Service
|
|
53
|
+
*
|
|
54
|
+
* Provides translation loading via HTTP backend. Both development and production
|
|
55
|
+
* use HTTP to load translations consistently.
|
|
56
|
+
*
|
|
57
|
+
* In development, translations are served by @kokimoki/kit's dev server middleware.
|
|
58
|
+
* In production, translations are served from the assets CDN.
|
|
59
|
+
*
|
|
60
|
+
* **Key Features:**
|
|
61
|
+
* - Pre-configured i18next instance creation
|
|
62
|
+
* - Consistent HTTP-based loading in dev and prod
|
|
63
|
+
* - URL resolution for translation namespaces
|
|
64
|
+
* - AI-powered translation requests with polling support
|
|
65
|
+
*
|
|
66
|
+
* Access via `kmClient.i18n`
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* // Setup with React
|
|
71
|
+
* import { initReactI18next } from 'react-i18next';
|
|
72
|
+
*
|
|
73
|
+
* export const i18n = kmClient.i18n.createI18n({
|
|
74
|
+
* use: [initReactI18next]
|
|
75
|
+
* });
|
|
76
|
+
*
|
|
77
|
+
* // Initialize with primary language
|
|
78
|
+
* await kmClient.i18n.init('en');
|
|
79
|
+
*
|
|
80
|
+
* // Request AI translation and wait for it
|
|
81
|
+
* await kmClient.i18n.requestTranslation('de');
|
|
82
|
+
* await kmClient.i18n.pollTranslation('de', {
|
|
83
|
+
* onProgress: (status) => console.log('Translation status:', status.status)
|
|
84
|
+
* });
|
|
85
|
+
*
|
|
86
|
+
* // Now safe to switch language
|
|
87
|
+
* i18next.changeLanguage('de');
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export declare class KokimokiI18nService {
|
|
91
|
+
private readonly client;
|
|
92
|
+
private initPromise;
|
|
93
|
+
private instance;
|
|
94
|
+
private options;
|
|
95
|
+
constructor(client: KokimokiClient);
|
|
96
|
+
/**
|
|
97
|
+
* Create and configure an i18next instance.
|
|
98
|
+
*
|
|
99
|
+
* This sets up the instance with plugins but does NOT initialize it.
|
|
100
|
+
* Call `init(lng)` to initialize with a specific language.
|
|
101
|
+
*
|
|
102
|
+
* @param options - Configuration options (plugins, fallback, defaultNS)
|
|
103
|
+
* @returns Configured i18next instance (not yet initialized)
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```typescript
|
|
107
|
+
* // With React
|
|
108
|
+
* import { initReactI18next } from 'react-i18next';
|
|
109
|
+
*
|
|
110
|
+
* export const i18n = kmClient.i18n.createI18n({
|
|
111
|
+
* use: [initReactI18next]
|
|
112
|
+
* });
|
|
113
|
+
*
|
|
114
|
+
* // Later, when you know the language:
|
|
115
|
+
* await kmClient.i18n.init('en');
|
|
116
|
+
*
|
|
117
|
+
* // Then in components:
|
|
118
|
+
* const { t } = useTranslation('game');
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
createI18n(options?: I18nOptions): i18n;
|
|
122
|
+
/**
|
|
123
|
+
* Initialize the i18next instance with a specific language.
|
|
124
|
+
*
|
|
125
|
+
* Must call `createI18n()` first to set up the instance.
|
|
126
|
+
*
|
|
127
|
+
* @param lng - The language code to initialize with (e.g., 'en', 'de')
|
|
128
|
+
* @returns Promise that resolves when i18n is ready
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```typescript
|
|
132
|
+
* // Create instance first
|
|
133
|
+
* const i18n = kmClient.i18n.createI18n({ use: [initReactI18next] });
|
|
134
|
+
*
|
|
135
|
+
* // Then initialize when you know the language
|
|
136
|
+
* await kmClient.i18n.init('en');
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
init(lng: string): Promise<void>;
|
|
140
|
+
/**
|
|
141
|
+
* Get the URL for a translation namespace.
|
|
142
|
+
*
|
|
143
|
+
* Returns the appropriate URL based on environment and language source:
|
|
144
|
+
* - Development (local language): `/__kokimoki/i18n/{lng}/{ns}.json`
|
|
145
|
+
* - Development (AI-translated): `{buildUrl}km-i18n/{lng}/{ns}.json`
|
|
146
|
+
* - Production: `{assets}/km-i18n/{lng}/{ns}.json`
|
|
147
|
+
*
|
|
148
|
+
* @param lng - Language code (e.g., 'en', 'et', 'de')
|
|
149
|
+
* @param ns - Namespace (e.g., 'ui', 'game', 'setup')
|
|
150
|
+
* @returns Full URL to the translation JSON file
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```typescript
|
|
154
|
+
* const url = kmClient.i18n.getNamespaceUrl('en', 'game');
|
|
155
|
+
* // Dev (local): "/__kokimoki/i18n/en/game.json"
|
|
156
|
+
* // Dev (AI): "https://builds.kokimoki.com/build-123/km-i18n/de/game.json"
|
|
157
|
+
* // Prod: "https://cdn.kokimoki.com/build-123/km-i18n/en/game.json"
|
|
158
|
+
* ```
|
|
159
|
+
*/
|
|
160
|
+
getNamespaceUrl(lng: string, ns: string): string;
|
|
161
|
+
/**
|
|
162
|
+
* Get the list of available namespaces.
|
|
163
|
+
*
|
|
164
|
+
* @returns Array of namespace names configured in @kokimoki/kit
|
|
165
|
+
*/
|
|
166
|
+
getNamespaces(): string[];
|
|
167
|
+
/**
|
|
168
|
+
* Get the list of available languages.
|
|
169
|
+
*
|
|
170
|
+
* @returns Array of language codes configured in @kokimoki/kit
|
|
171
|
+
*/
|
|
172
|
+
getLanguages(): string[];
|
|
173
|
+
/**
|
|
174
|
+
* Get the status of all languages that have been requested for AI translation.
|
|
175
|
+
*
|
|
176
|
+
* @returns Promise with array of language statuses
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```typescript
|
|
180
|
+
* const { languages } = await kmClient.i18n.getAllLanguagesStatus();
|
|
181
|
+
* // [{ lng: 'de', status: 'available' }, { lng: 'fr', status: 'processing' }]
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
getAllLanguagesStatus(): Promise<AllLanguagesStatus>;
|
|
185
|
+
/**
|
|
186
|
+
* Get the translation status for a specific language.
|
|
187
|
+
*
|
|
188
|
+
* Returns the overall status and per-namespace status for the given language.
|
|
189
|
+
*
|
|
190
|
+
* @param lng - Target language code (e.g., 'de', 'fr', 'es')
|
|
191
|
+
* @returns Promise with translation status
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```typescript
|
|
195
|
+
* const status = await kmClient.i18n.getTranslationStatus('de');
|
|
196
|
+
* if (status.status === 'available') {
|
|
197
|
+
* // All translations ready, can switch language
|
|
198
|
+
* i18next.changeLanguage('de');
|
|
199
|
+
* } else if (status.status === 'processing') {
|
|
200
|
+
* // Show loading indicator
|
|
201
|
+
* } else {
|
|
202
|
+
* // Request translation
|
|
203
|
+
* await kmClient.i18n.requestTranslation('de');
|
|
204
|
+
* }
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
207
|
+
getTranslationStatus(lng: string): Promise<TranslationStatus>;
|
|
208
|
+
/**
|
|
209
|
+
* Request AI translation for a target language.
|
|
210
|
+
*
|
|
211
|
+
* Triggers background AI translation jobs for all namespaces that are not yet available.
|
|
212
|
+
* Uses the build's configured primary language as the source.
|
|
213
|
+
*
|
|
214
|
+
* @param lng - Target language code (e.g., 'de', 'fr', 'es')
|
|
215
|
+
* @returns Promise with the result of the request
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* ```typescript
|
|
219
|
+
* const result = await kmClient.i18n.requestTranslation('de');
|
|
220
|
+
*
|
|
221
|
+
* if (result.status === 'already_available') {
|
|
222
|
+
* // Already translated, switch immediately
|
|
223
|
+
* i18next.changeLanguage('de');
|
|
224
|
+
* } else {
|
|
225
|
+
* // Poll until ready
|
|
226
|
+
* await kmClient.i18n.pollTranslation('de', {
|
|
227
|
+
* onProgress: (status) => console.log('Status:', status.status)
|
|
228
|
+
* });
|
|
229
|
+
* i18next.changeLanguage('de');
|
|
230
|
+
* }
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
requestTranslation(lng: string): Promise<RequestTranslationResult>;
|
|
234
|
+
/**
|
|
235
|
+
* Poll a translation request until all namespaces are available.
|
|
236
|
+
*
|
|
237
|
+
* @param lng - The language code to poll for.
|
|
238
|
+
* @param options - Polling options (interval, timeout, progress callback).
|
|
239
|
+
* @returns Promise that resolves when all namespaces are available.
|
|
240
|
+
* @throws If the translation fails or times out.
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* ```typescript
|
|
244
|
+
* // Request and poll with progress
|
|
245
|
+
* await kmClient.i18n.requestTranslation('de');
|
|
246
|
+
* await kmClient.i18n.pollTranslation('de', {
|
|
247
|
+
* timeout: 60000,
|
|
248
|
+
* onProgress: (status) => {
|
|
249
|
+
* console.log('Overall:', status.status);
|
|
250
|
+
* console.log('Namespaces:', status.namespaces);
|
|
251
|
+
* }
|
|
252
|
+
* });
|
|
253
|
+
*
|
|
254
|
+
* // Now safe to switch
|
|
255
|
+
* i18next.changeLanguage('de');
|
|
256
|
+
* ```
|
|
257
|
+
*/
|
|
258
|
+
pollTranslation(lng: string, options?: PollOptions<TranslationStatus>): Promise<void>;
|
|
259
|
+
}
|