Lingara Lingara مستندات راهنماها API کتابخانه‌ها برنامه‌ها ساخت جاسازی نسخهٔ وب
زبان: فارسی

ویجت وب‌سایت

این صفحه از انگلیسی ترجمه شده است. اگر این دو با هم تفاوت داشته باشند، صفحهٔ انگلیسی درست است. خواندن صفحهٔ انگلیسی

در یک وب‌سایت، Lingara به‌صورت یک عنصر سفارشی، <lingara-embed>، اجرا می‌شود. این عنصر تمرین Lingara را در فریمی که Lingara ارائه می‌دهد ترسیم می‌کند، پس صفحهٔ شما هرگز داده‌های زبان‌آموز را نمی‌بیند و صفحهٔ Lingara هرگز داده‌های شما را نمی‌بیند.

قرار دادن عنصر

@lingara/embed را از npm نصب کنید، یا اگر سایت شما bundler ندارد، نسخهٔ ماژول آن را از یک CDN بارگذاری کنید. سپس <lingara-embed> را روی صفحه بگذارید و آن را تعریف کنید. این عنصر این‌ها را می‌گیرد:

  • plan-id، برنامهٔ درسی برای تمرین، که مال بازیکن است؛
  • surface، آنچه نشان داده شود: practice، مقدار پیش‌فرض و تنها سطحی که وجود دارد؛
  • theme، یکی از light، dark یا auto؛
  • locale، زبان واژه‌های خود فریم، که در غیر این صورت از زبان‌آموز پیروی می‌کند؛
  • title، نام دسترس‌پذیر فریم.

سفارشی‌سازی ظاهر به پوسته محدود است. صفحهٔ شما نمی‌تواند به درون فریم دسترسی پیدا کند، و پوسته تنها تنظیمی است که فریم ارائه می‌دهد.

دادن توکن به آن

tokenProvider عنصر را روی تابعی تنظیم کنید که از سرور خودتان توکن درخواست می‌کند. سرور شما با یک کیت سرور توکن را برای مبدأ صفحه صادر می‌کند و با توکن و زمان انقضای آن پاسخ می‌دهد. عنصر توکن را از طریق پیام به فریم می‌دهد، و توکن هرگز در یک URL جابه‌جا نمی‌شود.

هر مبدأیی را که ویجت روی آن اجرا می‌شود پیش از صادر کردن توکن برای آن، در تنظیمات کلاینت خود در کنسول ثبت کنید. صفحهٔ کیت‌های سرور روش آن را می‌گوید. API توکنی را که برای هر مبدأ دیگری صادر شده باشد رد می‌کند و فریم به‌جای تمرین یک خطا نشان می‌دهد.

یک کیت سرور همچنین می‌تواند کل قطعه‌کد، عنصر و فراهم‌کنندهٔ توکن را با هم، برایتان بنویسد، همراه با nonce اسکریپت صفحهٔ شما اگر سیاست امنیت محتوای شما به آن نیاز داشته باشد. آخرین نمونهٔ پایین آن را نشان می‌دهد.

گوش دادن به آنچه فریم می‌گوید

فریم از طریق یک پروتکل پیام نسخه‌دار با عنصر صحبت می‌کند، و عنصر آنچه را صفحهٔ شما لازم دارد به رویدادهای DOM تبدیل می‌کند:

  • lingara:practice-completed وقتی زبان‌آموز یک مجموعه را تمام می‌کند، همراه با planId، setNumber، correct و total آن؛
  • lingara:error وقتی فریم متوقف می‌شود، همراه با یک code و retryable. خطای قابل تلاش دوباره یعنی یک بارگذاری تازه ممکن است موفق شود؛ اینکه چه زمانی دوباره تلاش کنید تصمیم خود شماست.

نتیجهٔ تمرین به سرور شما هم می‌رسد، همان‌طور که در نتایج تمرین توضیح داده شده است.

npm install @lingara/embed@0.1.0-alpha.6
# No bundler? One module script instead:
# <script type="module" src="https://cdn.jsdelivr.net/npm/@lingara/embed@0.1.0-alpha.6/dist/lingara-embed.min.js"></script>
<!-- plan-id is a lesson plan your server made for this player. -->
<lingara-embed surface="practice" plan-id="0b9d4f2e-3c1a-4e8b-9f6d-2a7c5e1b8d40" theme="auto" title="Practice"></lingara-embed>
<script type="module">
  import { defineLingaraEmbed } from '@lingara/embed'
  defineLingaraEmbed()
</script>
// Your own endpoint, on your own server. It mints with this page's origin and
// returns exactly { token, expires_at }: the token (lgr_et_…) never touches a URL.
widget.tokenProvider = async () => {
  const response = await fetch('/lingara/token', { method: 'POST', credentials: 'same-origin' })
  if (!response.ok) throw new Error(`token endpoint answered ${response.status}`)
  return response.json()
}
widget.addEventListener('lingara:practice-completed', (event) => {
  const { planId, setNumber, correct, total } = (event as CustomEvent).detail
  console.log(`set ${setNumber} of ${planId}: ${correct}/${total}`)
})
widget.addEventListener('lingara:error', (event) => {
  const { code, retryable } = (event as CustomEvent).detail
  // `retryable` means a remount may succeed; when to try is yours to decide.
  if (retryable) setTimeout(() => widget.reload(), 30_000)
  else console.warn('Lingara practice stopped:', code)
})
زبان نمونه‌کد

TypeScript

// The page that mounts the widget: the token never appears in it.
export function practicePage(planId: string, cspNonce: string): string {
  const widget = widgetSnippet({ planId, tokenEndpoint: '/lingara/token', theme: 'auto', locale: 'fr', title: 'Pratique', nonce: cspNonce })
  return `<!doctype html><title>Practice</title>${widget}`
}

Rust

// The element, its script build and a token provider that POSTs to your
// token route. The token never appears in the markup.
let html = widget_snippet(&SnippetOptions {
    locale: Some("fr".into()),
    nonce: Some(csp_nonce.into()), // your page's CSP nonce, for a strict script-src
    ..SnippetOptions::new(plan_id, "/lingara/token")
})?;

Go

// The plan your server made for this player, and the token route above.
// Pass the request's CSP nonce when your script-src allows no inline
// script; the token itself never appears in the markup.
theme := "auto"
html, err := lingaraembed.WidgetSnippet(lingaraembed.SnippetOptions{
	PlanID:        planID,
	TokenEndpoint: "/lingara/token",
	Theme:         &theme,
	Nonce:         &cspNonce,
})
if err != nil {
	return "", err // a *lingaraembed.SnippetError names the refused option
}
return template.HTML(html), nil // already escaped by the kit

Java

// planId is the lesson plan your server made for this player. The element
// POSTs to tokenEndpoint with same-origin cookies: the token never appears
// in the markup. Pass this request's CSP nonce if your page sets one.
String html =
    WidgetSnippet.render(
        SnippetOptions.builder(planId, "/lingara/token").locale("fr").nonce(cspNonce).build());

Kotlin

// planId is the lesson plan your server made for this player. The element
// POSTs to tokenEndpoint with same-origin cookies: the token never appears
// in the markup. Pass this request's CSP nonce if your page sets one.
val html =
    widgetSnippet(
        SnippetOptions(planId, tokenEndpoint = "/lingara/token").apply {
            locale = "fr"
            nonce = cspNonce
        },
    )

Ruby

# The plan your server made for this player, rendered into your page.
# nonce: your page's CSP nonce, when its script-src allows no inline script.
def self.widget(plan_id, csp_nonce)
  Lingara::Embed.widget_snippet(plan_id: plan_id, token_endpoint: "/lingara/token", locale: "fr", nonce: csp_nonce)
end

PHP

use Lingara\Embed\SnippetOptions;
use Lingara\Embed\WidgetSnippet;

// In your page's template: the plan your server made for this player, and
// your token route. Pass the request's CSP nonce if your script-src allows
// no inline script. A bad option throws SnippetException naming its field.
function practiceWidget(string $planId, string $cspNonce): string
{
    return WidgetSnippet::render(new SnippetOptions(
        planId: $planId,
        tokenEndpoint: '/lingara/token',
        theme: 'auto',
        nonce: $cspNonce,
    ));
}

C#

app.MapGet("/practice/{planId}", (string planId, HttpContext http) =>
{
    var widget = WidgetSnippet.Render(new SnippetOptions
    {
        PlanId = planId,                              // the plan your server made for this player
        TokenEndpoint = "/lingara/token",             // same origin: the element sends this page's cookies
        Nonce = http.Items["csp-nonce"] as string,     // your CSP's nonce, if script-src has one
    });
    return Results.Content($"<!doctype html><title>Practice</title>\n{widget}", "text/html");
}).RequireAuthorization();