III.3
Translate strings with AI
You need this: Multilingual forms.
The Translations tab can request machine translation. Creator passes you the strings and the locales; your endpoint calls the AI provider you choose with your own key, and the author reviews the result. Nothing goes to SurveyJS.
This step on the Server Integration page
Source on GitHub
Commercial client licence: without SURVEYJS_LICENSE_KEY the component shows a licence banner
Try this
Code that just ran
These regions are read from the files that served this page, the same lines the Server Integration page shows.
shared/client/ai-translation.js · sjs:III.3.client
View on GitHub
// Creator asks for machine translation; your server calls the AI provider
creator.onMachineTranslate.add(async (_, options) => {
const res = await fetch("/api/translate", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ strings: options.strings, from: options.fromLocale, to: options.toLocale })
});
options.callback(res.ok ? await res.json() : []); // same order as options.strings; [] when it failed
});
routes/examples/ai-translation.php · sjs:III.3.server
View on GitHub
// POST /api/translate — strings in, translated strings out (same order); nothing goes to SurveyJS
Route::post('/api/translate', function (Request $request) {
abort_unless(config('surveyjs.ai.api_key'), 501, 'Set AI_API_KEY to enable translation');
['strings' => $strings, 'from' => $from, 'to' => $to] = $request->only(['strings', 'from', 'to']) + ['strings' => [], 'from' => '', 'to' => ''];
$reply = Http::baseUrl(config('surveyjs.ai.base_url'))->withToken(config('surveyjs.ai.api_key'))->timeout(60)
->post('/chat/completions', [ // any OpenAI-compatible provider: your key, your choice
'model' => config('surveyjs.ai.model'),
'messages' => [
['role' => 'system', 'content' => "Translate each string from {$from} to {$to}. Return a JSON array in the same order."],
['role' => 'user', 'content' => json_encode(array_values($strings), JSON_UNESCAPED_UNICODE)],
],
])->throw();
// Models sometimes wrap the array in prose or a code fence: take the array itself
preg_match('/\[.*\]/s', (string) $reply->json('choices.0.message.content'), $match);
$translated = json_decode($match[0] ?? 'null');
abort_unless(is_array($translated) && count($translated) === count($strings), 502, 'The AI provider returned an unexpected answer');
return response()->json($translated); // what options.callback() takes
});
Definition: shared/definitions/creator-load-save.json