Lingara Lingara 문서 학습 가이드 API 라이브러리 앱 만들기 웹 앱
언어: 한국어

컨텍스트와 동의

이 페이지는 영어에서 번역되었습니다. 두 내용이 다를 경우 영어 페이지가 정확합니다. 영어 페이지 읽기

앱은 오직 컨텍스트 슬라이스를 통해서만 학습자에 대해 알 수 있습니다. 각 슬라이스는 고정된 필드를 가진 작은 레코드입니다. 매니페스트에 요청할 슬라이스를 나열하면, 학습자는 앱을 설치할 때 각 슬라이스에 동의하며, Lingara는 두 조건이 모두 유지되는 동안에만 슬라이스를 보냅니다.

슬라이스

슬라이스필드담긴 내용
languagessource_lang학습자가 학습의 기준으로 삼는 언어로, en과 같은 언어 태그입니다.
target_lang학습자가 배우고 있는 언어.
level그 언어에서의 레벨로, 1부터 9까지이며 학습자가 설정한 경우에만 있습니다.
plan_summaryplan_id학습자의 최신 수업 계획 ID로, 계획을 서로 구별하는 데 쓰입니다. 앱은 이 ID로 계획을 가져올 수 없습니다. 앱의 토큰은 학습자의 계정이 아니라 개발자 본인의 계정을 읽기 때문입니다.
title생성된 계획 제목으로, 최대 120자이며 제목이 있는 경우에만 있습니다.
target_lang계획이 가르치는 언어.
set_count계획에 포함된 세트 수로, 최대 200입니다.
sets_completed그중 학습자가 완료한 세트 수.
review_duedue지금 복습할 플래시카드 수로, 최대 100000입니다.
learned학습자가 익힌 단어 수로, 최대 100000입니다.
tutor_topictopic학습자의 최신 튜터 채팅 주제로, 1자에서 120자까지입니다. 계획의 제목이나 학습자가 보고 있는 화면에서 가져오며, 학습자가 직접 쓴 말에서 가져오는 일은 절대 없습니다.

어떤 슬라이스에도 없는 것

어떤 슬라이스에도 이메일 주소, 이름, 사용자 ID, 학습자가 입력한 내용은 담기지 않습니다. 앱은 요청의 subject를 통해 학습자가 누구인지 알 수 있으며, 이 값은 안정적이고 앱마다 다릅니다. 앱의 토큰은 개발자 본인의 계정을 읽을 뿐 학습자의 계정은 절대 읽지 않으므로, 앱이 학습자에 대해 아는 것은 슬라이스가 전부입니다.

동의

  • 학습자는 앱을 설치할 때 각 슬라이스에 동의합니다. 동의한 내용을 바꾸려면 앱을 제거한 뒤 다시 설치합니다.
  • 매니페스트를 수정해 요청하는 슬라이스를 줄이면, 제외한 슬라이스는 즉시 전송이 중단됩니다.
  • 매니페스트를 수정해 요청하는 슬라이스를 늘리면, 새 슬라이스는 학습자가 다시 설치할 때까지 어떤 학습자에게도 전달되지 않습니다.
  • Lingara는 요청마다 동의를 다시 확인하고, 학습자가 동의하지 않았거나 매니페스트가 더 이상 요청하지 않는 슬라이스를 버립니다. 레코드에 맞지 않는 슬라이스도 버려지지만, 요청 전체가 버려지는 일은 없습니다.

아래 샘플은 전달받은 슬라이스로 한 줄을 만들며 API는 호출하지 않습니다.

코드 예제 언어

TypeScript

// The app's own client reads its owner's account, never the learner's. The
// slices are all a render knows about the learner.
function planLine(request: AppRenderRequest): string {
  let line = "";
  for (const slice of request.context) {
    // A slice is present only when the learner agreed to share it.
    if (slice.kind === "languages") line += `${slice.source_lang} → ${slice.target_lang}. `;
    if (slice.kind === "plan_summary") line += `${slice.sets_completed}/${slice.set_count} sets.`;
  }
  return line;
}

Rust

// The app's own client reads its owner's account, never the learner's. The
// slices are all a render knows about the learner.
/// The learner's target language and, when they shared their plan, its
/// `(sets_completed, set_count)`.
fn shared_plan(request: &AppRenderRequest) -> (String, Option<(u32, u32)>) {
    let (mut target_lang, mut progress) = (String::from("zh"), None);
    for slice in &request.context {
        match slice {
            ContextSlice::Languages(languages) => target_lang = languages.target_lang.clone(),
            ContextSlice::PlanSummary(summary) => progress = Some((summary.sets_completed, summary.set_count)),
            _ => {}
        }
    }
    (target_lang, progress)
}

Go

// The app's own client reads its owner's account, never the learner's.
// The slices are all a render knows about the learner.
//
// Each slice is present only when the learner agreed to share it.
card := lingaraapps.NewCard().Heading("Your plan", 1)
for _, slice := range req.Context {
	switch s := slice.(type) {
	case lingaraapps.ContextSliceLanguages:
		card.Text(fmt.Sprintf("Learning %s from %s", s.TargetLang, s.SourceLang))
	case lingaraapps.ContextSlicePlanSummary:
		card.Text(fmt.Sprintf("%d of %d sets done", s.SetsCompleted, s.SetCount))
	}
}

Java

import com.getlingara.apps.Card;
import com.getlingara.apps.Reply;
import com.getlingara.apps.model.AppRenderRequest;
import com.getlingara.apps.model.ContextSlice;
import com.getlingara.apps.model.ContextSliceLanguages;
import com.getlingara.apps.model.ContextSlicePlanSummary;

// The app's own client reads its owner's account, never the learner's. The slices are all a
// render knows about the learner.
static Reply render(AppRenderRequest request) {
  Card.Builder card = Card.card();
  // A slice is present only when the learner agreed to share it; the context is read-only.
  for (ContextSlice slice : request.getContext()) {
    if (slice instanceof ContextSliceLanguages languages) {
      card.heading("Learning " + languages.targetLang(), 1);
    } else if (slice instanceof ContextSlicePlanSummary summary) {
      card.text(summary.setsCompleted() + " of " + summary.setCount() + " sets done");
    }
  }
  return card.heading("Today", 2).build();
}

Kotlin

import com.getlingara.apps.kotlin.Reply
import com.getlingara.apps.kotlin.card
import com.getlingara.apps.kotlin.model.AppRenderRequest
import com.getlingara.apps.kotlin.model.ContextSliceLanguages
import com.getlingara.apps.kotlin.model.ContextSlicePlanSummary

// The app's own client reads its owner's account, never the learner's. The slices are all a
// render knows about the learner.
fun renderWithContext(request: AppRenderRequest): Reply {
    // A slice is present only when the learner agreed to share it; the context is read-only.
    val languages = request.context.filterIsInstance<ContextSliceLanguages>().firstOrNull()
    val summary = request.context.filterIsInstance<ContextSlicePlanSummary>().firstOrNull()
    return card {
        heading("Learning ${languages?.targetLang ?: "today"}", 1)
        if (summary != null) {
            text("${summary.setsCompleted} of ${summary.setCount} sets done")
        }
    }
}

Ruby

# The app's own client reads its owner's account, never the learner's. The
# slices are all a render knows about the learner.
#
# A slice is present only when the learner agreed to share it.
request.context.filter_map do |slice|
  case slice
  in Lingara::Apps::ContextSliceLanguages(source_lang:, target_lang:)
    "#{source_lang} → #{target_lang}."
  in Lingara::Apps::ContextSlicePlanSummary(sets_completed:, set_count:)
    "#{sets_completed}/#{set_count} sets."
  else nil
  end
end.join(" ")

PHP

use Lingara\Apps\Generated\ContextSliceLanguages;
use Lingara\Apps\Generated\ContextSlicePlanSummary;

function planLine(AppRenderRequest $request): string
{
    // The app's own client reads its owner's account, never the learner's. The
    // slices are all a render knows about the learner.
    $line = '';
    // A slice is present only when the learner agreed to share it.
    foreach ($request->getContext() as $slice) {
        if ($slice instanceof ContextSliceLanguages) {
            $line .= "{$slice->sourceLang} → {$slice->targetLang}. ";
        } elseif ($slice instanceof ContextSlicePlanSummary) {
            $line .= "{$slice->setsCompleted}/{$slice->setCount} sets.";
        }
    }
    return $line;
}

함께 보기