Lingara Lingara Dokumentasyon Mga gabay API Mga library Mga app Gumawa Embed Web app
Wika: Filipino

Widget para sa website

Isinalin mula sa Ingles ang pahinang ito. Kung magkaiba ang dalawa, ang pahinang Ingles ang tama. Basahin ang pahinang Ingles

Sa isang website, tumatakbo ang Lingara bilang isang custom element, ang <lingara-embed>. Iginuguhit ng element ang pagsasanay ng Lingara sa isang frame na inihahatid ng Lingara, kaya hindi kailanman nakikita ng iyong page ang data ng learner at hindi kailanman nakikita ng page ng Lingara ang sa iyo.

I-mount ang element

I-install ang @lingara/embed mula sa npm, o i-load ang module build nito mula sa isang CDN kung walang bundler ang iyong site. Pagkatapos, ilagay ang <lingara-embed> sa page at i-define ito. Tumatanggap ang element ng:

  • plan-id, ang plano ng aralin na sasanayin, isang pagmamay-ari ng player;
  • surface, kung ano ang ipapakita: practice, ang default at ang nag-iisang surface na mayroon;
  • theme, isa sa light, dark o auto;
  • locale, ang wika ng sariling mga salita ng frame, na kung hindi itatakda ay sumusunod sa learner;
  • title, ang accessible name ng frame.

Hanggang sa theme lang ang styling. Hindi kayang abutin ng iyong page ang loob ng frame, at ang theme ang nag-iisang setting na iniaalok nito.

Bigyan ito ng mga token

Itakda ang tokenProvider ng element sa isang function na humihingi ng token sa sarili mong server. Mina-mint ito ng iyong server gamit ang origin ng page, gamit ang isang server kit, at sumasagot gamit ang token at ang expiry nito. Iniaabot ng element ang token sa frame sa pamamagitan ng mensahe, at hindi ito kailanman dumadaan sa isang URL.

Irehistro ang bawat origin na pinapatakbuhan ng widget bago ka mag-mint para dito, sa mga setting ng iyong client sa console. Sinasabi ng page na mga server kit kung paano. Tinatanggihan ng API ang token na mina-mint para sa anumang ibang origin, at nagpapakita ang frame ng error sa halip na pagsasanay.

Kaya ring isulat ng isang server kit ang buong snippet para sa iyo, ang element at ang token provider nang magkasama, kasama ang script nonce ng iyong page kung kailangan ito ng iyong content security policy. Ipinapakita ito ng huling sample sa ibaba.

Pakinggan ang sinasabi ng frame

Nakikipag-usap ang frame sa element sa pamamagitan ng isang versioned na message protocol, at ginagawa ng element na mga DOM event ang kailangan ng iyong page:

  • lingara:practice-completed kapag natapos ng learner ang isang set, kasama ang planId, setNumber, correct at total nito;
  • lingara:error kapag huminto ang frame, kasama ang isang code at retryable. Ang retryable na error ay nangangahulugang puwedeng magtagumpay ang isang bagong mount; ikaw ang magpapasya kung kailan muling susubok.

Umaabot din sa iyong server ang resulta ng pagsasanay, gaya ng inilalarawan sa mga resulta ng pagsasanay.

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)
})
Wika ng halimbawang 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();