add nihongo grammar app
This commit is contained in:
920
apps/nihongo/configmap.yaml
Normal file
920
apps/nihongo/configmap.yaml
Normal file
@@ -0,0 +1,920 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: nihongo-html
|
||||
namespace: nihongo
|
||||
data:
|
||||
index.html: |
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Kody Sensei — CM_7-5 Übung</title>
|
||||
<style>
|
||||
:root{
|
||||
--orange:#f2c58a; --orange-d:#e6a94f; --ink:#4a4a4a; --ink-soft:#6d6d6d;
|
||||
--blue:#2f7fd6; --wo:#c0392b; --green:#2e8b57; --bg:#fbf7f0; --card:#fff;
|
||||
--line:#ece3d5; --shadow:0 4px 18px rgba(0,0,0,.08);
|
||||
}
|
||||
*{box-sizing:border-box}
|
||||
body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Noto Sans JP",sans-serif;
|
||||
background:var(--bg);color:var(--ink);line-height:1.55}
|
||||
header{background:var(--orange);padding:14px 20px;display:flex;align-items:center;gap:12px;
|
||||
box-shadow:var(--shadow);position:sticky;top:0;z-index:10}
|
||||
header .dog{font-size:28px}
|
||||
header h1{font-size:17px;margin:0;font-weight:800;color:#555}
|
||||
header .sub{font-size:12px;color:#7a5b1e;margin-top:2px}
|
||||
.wrap{max-width:660px;margin:0 auto;padding:18px}
|
||||
nav{display:flex;gap:8px;margin-bottom:18px;flex-wrap:wrap}
|
||||
.lessonbar{display:flex;align-items:center;gap:10px;margin-bottom:12px;background:#fff;
|
||||
border-radius:12px;box-shadow:var(--shadow);padding:10px 14px}
|
||||
.lessonbar label{font-size:13px;font-weight:700;color:var(--ink-soft);white-space:nowrap}
|
||||
.lessonbar select{flex:1}
|
||||
nav button{flex:1;min-width:84px;border:none;border-radius:12px;padding:10px 6px;font-size:13px;
|
||||
font-weight:700;cursor:pointer;background:#fff;color:var(--ink-soft);box-shadow:var(--shadow);
|
||||
transition:.15s}
|
||||
nav button.active{background:var(--orange-d);color:#fff}
|
||||
.card{background:var(--card);border-radius:18px;box-shadow:var(--shadow);padding:26px 22px;margin-bottom:16px}
|
||||
.prompt-label{font-size:12px;text-transform:uppercase;letter-spacing:.08em;color:var(--orange-d);
|
||||
font-weight:800;margin-bottom:8px}
|
||||
.de{font-size:21px;font-weight:600}
|
||||
.en{font-size:14px;color:var(--ink-soft);margin-top:4px;font-style:italic}
|
||||
.q{font-size:13px;color:var(--orange-d);font-weight:700;margin-top:8px}
|
||||
.jp{font-size:30px;margin:16px 0 6px;font-weight:600}
|
||||
.jp ruby rt{font-size:.5em;color:var(--ink-soft);font-weight:400}
|
||||
.reading{font-size:16px;color:var(--ink-soft)}
|
||||
.hidden{display:none}
|
||||
.btn{display:inline-block;border:none;border-radius:12px;padding:13px 20px;font-size:15px;font-weight:700;
|
||||
cursor:pointer;transition:.12s}
|
||||
.btn:active{transform:translateY(1px)}
|
||||
.btn-primary{background:var(--orange-d);color:#fff;width:100%}
|
||||
.btn-row{display:flex;gap:10px;margin-top:16px}
|
||||
.btn-ok{background:var(--green);color:#fff;flex:1}
|
||||
.btn-no{background:var(--wo);color:#fff;flex:1}
|
||||
.p-ni{color:var(--blue);font-weight:800}
|
||||
.p-wo{color:var(--wo);font-weight:800}
|
||||
.p-de{color:#8e44ad;font-weight:800}
|
||||
.p-ga{color:#2e8b57;font-weight:800}
|
||||
.p-wa{color:#b8860b;font-weight:800}
|
||||
.grammarnote{background:#fff;border-radius:12px;box-shadow:var(--shadow);padding:12px 16px;margin-bottom:14px;
|
||||
font-size:14px;border-left:4px solid var(--orange-d)}
|
||||
.grammarnote b{color:var(--orange-d)}
|
||||
.progress{height:8px;background:#eee;border-radius:99px;overflow:hidden;margin-bottom:14px}
|
||||
.progress > div{height:100%;background:var(--orange-d);width:0;transition:.3s}
|
||||
.meta{display:flex;justify-content:space-between;font-size:13px;color:var(--ink-soft);margin-bottom:14px}
|
||||
.note{font-size:13px;color:var(--ink-soft);background:#fbf3e4;border-left:4px solid var(--orange-d);
|
||||
padding:10px 14px;border-radius:8px;margin-top:14px;line-height:1.5}
|
||||
.blanks{font-size:26px;line-height:2.1;margin:14px 0}
|
||||
.slot{display:inline-block;min-width:46px;border-bottom:3px solid var(--orange-d);text-align:center;
|
||||
cursor:pointer;color:#bbb}
|
||||
.slot.filled{color:var(--ink);border-color:var(--green)}
|
||||
.choices{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px}
|
||||
.choices button{border:2px solid var(--line);background:#fff;border-radius:10px;padding:8px 16px;
|
||||
font-size:20px;cursor:pointer;font-weight:700}
|
||||
.feedback{margin-top:14px;font-weight:700}
|
||||
.done{text-align:center;padding:30px}
|
||||
.done .big{font-size:44px}
|
||||
.barctl{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;gap:10px}
|
||||
select.sel{border:2px solid var(--line);border-radius:10px;padding:6px 10px;font-size:13px;background:#fff;color:var(--ink)}
|
||||
.tip{font-size:12px;color:var(--ink-soft);text-align:center;margin-top:8px}
|
||||
input.type{width:100%;font-size:22px;padding:12px 14px;border:2px solid var(--line);border-radius:12px;
|
||||
margin-top:14px;text-align:center;font-family:inherit}
|
||||
input.type:focus{outline:none;border-color:var(--orange-d)}
|
||||
input.type.ok{border-color:var(--green);background:#f0fbf4}
|
||||
input.type.bad{border-color:var(--wo);background:#fdf0ee}
|
||||
.boxes{display:inline-flex;gap:3px;vertical-align:middle;margin-left:6px}
|
||||
.boxes i{width:8px;height:8px;border-radius:2px;background:#e2d8c8}
|
||||
.boxes i.on{background:var(--orange-d)}
|
||||
.phrase{background:#fff;border-radius:14px;box-shadow:var(--shadow);padding:14px 16px;margin-bottom:10px}
|
||||
.phrase .jp{font-size:22px;margin:0 0 2px}
|
||||
.phrase .reading{font-size:13px}
|
||||
.phrase .de{font-size:15px;color:var(--ink);margin-top:4px;font-weight:500}
|
||||
h2.section{font-size:16px;color:var(--orange-d);margin:22px 0 10px}
|
||||
ul.beh{padding-left:18px;margin:0}
|
||||
ul.beh li{margin-bottom:8px;font-size:14px}
|
||||
.tiles{display:flex;gap:10px;margin-bottom:6px}
|
||||
.tile{flex:1;background:#fff;border-radius:14px;box-shadow:var(--shadow);padding:16px 10px;text-align:center}
|
||||
.tile b{display:block;font-size:26px;color:var(--orange-d)}
|
||||
.tile span{font-size:12px;color:var(--ink-soft)}
|
||||
.row{display:flex;align-items:center;justify-content:space-between;background:#fff;border-radius:12px;
|
||||
box-shadow:var(--shadow);padding:10px 14px;margin-bottom:8px;gap:10px}
|
||||
.row .lbl{font-size:17px}
|
||||
.row .rt{font-size:13px;color:var(--ink-soft);white-space:nowrap}
|
||||
.row .rt .ok{color:var(--green);font-weight:700}
|
||||
.row .rt .bad{color:var(--wo);font-weight:700}
|
||||
.btn-reset{background:#f0ece4;color:var(--ink-soft);width:100%;margin-top:8px}
|
||||
.empty{text-align:center;color:var(--ink-soft);padding:26px}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<span class="dog">🐕</span>
|
||||
<div><h1>CM_7-5 · The Purpose of Movement</h1>
|
||||
<div class="sub">Kody Sensei — Übung für Dominik · ~に ~を ~に いきます</div></div>
|
||||
</header>
|
||||
|
||||
<div class="wrap">
|
||||
<div class="lessonbar">
|
||||
<label for="lessonSel">📚 Lektion</label>
|
||||
<select id="lessonSel" class="sel"></select>
|
||||
</div>
|
||||
<nav>
|
||||
<button data-mode="review" class="active">🔁 Wiederholen</button>
|
||||
<button data-mode="stats">📊 Fortschritt</button>
|
||||
<button data-mode="unterricht">🗣️ Unterricht</button>
|
||||
<button data-mode="vocab">📇 Vokabeln</button>
|
||||
<button data-mode="verbstem">🔀 ますStamm</button>
|
||||
<button data-mode="sentence">✍️ Satzbau</button>
|
||||
<button data-mode="particle">🧩 Partikel</button>
|
||||
</nav>
|
||||
|
||||
<div id="grammarNote" class="grammarnote" style="display:none"></div>
|
||||
<div class="progress"><div id="bar"></div></div>
|
||||
<div class="meta"><span id="counter"></span><span id="score"></span></div>
|
||||
|
||||
<div id="app"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* ================= DATEN ================= */
|
||||
const VOCAB = [
|
||||
{jpr:'<ruby>食<rt>た</rt></ruby>べる', read:"たべる(たべます)", de:"essen", en:"to eat", kana:"たべる"},
|
||||
{jpr:'<ruby>飲<rt>の</rt></ruby>む', read:"のむ(のみます)", de:"trinken", en:"to drink", kana:"のむ"},
|
||||
{jpr:'<ruby>作<rt>つく</rt></ruby>る', read:"つくる(つくります)", de:"machen / kochen", en:"to make", kana:"つくる"},
|
||||
{jpr:'<ruby>行<rt>い</rt></ruby>く', read:"いく(いきます)", de:"gehen", en:"to go", kana:"いく"},
|
||||
{jpr:'<ruby>働<rt>はたら</rt></ruby>く', read:"はたらく(はたらきます)", de:"arbeiten", en:"to work", kana:"はたらく"},
|
||||
{jpr:'<ruby>掃除<rt>そうじ</rt></ruby>する', read:"そうじする(そうじします)", de:"putzen / saubermachen", en:"to clean", kana:"そうじする"},
|
||||
{jpr:'<ruby>仕事<rt>しごと</rt></ruby>', read:"しごと", de:"Arbeit / Job", en:"work, job", kana:"しごと"},
|
||||
{jpr:'<ruby>地下室<rt>ちかしつ</rt></ruby>', read:"ちかしつ", de:"Keller", en:"basement", kana:"ちかしつ"},
|
||||
{jpr:'<ruby>晩<rt>ばん</rt></ruby>ご<ruby>飯<rt>はん</rt></ruby>', read:"ばんごはん", de:"Abendessen", en:"dinner", kana:"ばんごはん"},
|
||||
{jpr:'ラーメン', read:"らーめん", de:"Ramen", en:"ramen", kana:"らーめん"},
|
||||
{jpr:'<ruby>抹茶<rt>まっちゃ</rt></ruby>', read:"まっちゃ", de:"Matcha", en:"matcha", kana:"まっちゃ"},
|
||||
{jpr:'コーヒー', read:"こーひー", de:"Kaffee", en:"coffee", kana:"こーひー"},
|
||||
{jpr:'カフェ', read:"かふぇ", de:"Café", en:"café", kana:"かふぇ"},
|
||||
{jpr:'レストラン', read:"れすとらん", de:"Restaurant", en:"restaurant", kana:"れすとらん"},
|
||||
{jpr:'<ruby>家<rt>うち</rt></ruby>', read:"うち", de:"Zuhause", en:"home", kana:"うち"},
|
||||
{jpr:'<ruby>昨日<rt>きのう</rt></ruby>', read:"きのう", de:"gestern", en:"yesterday", kana:"きのう"},
|
||||
{jpr:'<ruby>時々<rt>ときどき</rt></ruby>', read:"ときどき", de:"manchmal", en:"sometimes", kana:"ときどき"},
|
||||
{jpr:'<ruby>毎朝<rt>まいあさ</rt></ruby>', read:"まいあさ", de:"jeden Morgen", en:"every morning", kana:"まいあさ"},
|
||||
{jpr:'<ruby>毎晩<rt>まいばん</rt></ruby>', read:"まいばん", de:"jeden Abend", en:"every night", kana:"まいばん"},
|
||||
{jpr:'ちなみに', read:"ちなみに", de:"übrigens", en:"by the way", kana:"ちなみに"},
|
||||
{jpr:'きれい', read:"きれい", de:"sauber / schön", en:"clean, pretty", kana:"きれい"},
|
||||
];
|
||||
|
||||
const VERBS = [
|
||||
{jpr:'<ruby>食<rt>た</rt></ruby>べる', de:"essen", group:"Gruppe 2 (ru-Verb)", stemr:'<ruby>食<rt>た</rt></ruby>べ', stemKana:"たべ", masur:'<ruby>食<rt>た</rt></ruby>べます', rule:"ru-Verb: einfach る weg → たべ"},
|
||||
{jpr:'<ruby>見<rt>み</rt></ruby>る', de:"sehen", group:"Gruppe 2 (ru-Verb)", stemr:'<ruby>見<rt>み</rt></ruby>', stemKana:"み", masur:'<ruby>見<rt>み</rt></ruby>ます', rule:"ru-Verb: る weg → み"},
|
||||
{jpr:'<ruby>飲<rt>の</rt></ruby>む', de:"trinken", group:"Gruppe 1 (u-Verb)", stemr:'<ruby>飲<rt>の</rt></ruby>み', stemKana:"のみ", masur:'<ruby>飲<rt>の</rt></ruby>みます', rule:"u-Verb: む → み"},
|
||||
{jpr:'<ruby>作<rt>つく</rt></ruby>る', de:"machen", group:"Gruppe 1 (u-Verb)", stemr:'<ruby>作<rt>つく</rt></ruby>り', stemKana:"つくり", masur:'<ruby>作<rt>つく</rt></ruby>ります', rule:"u-Verb: る → り"},
|
||||
{jpr:'<ruby>行<rt>い</rt></ruby>く', de:"gehen", group:"Gruppe 1 (u-Verb)", stemr:'<ruby>行<rt>い</rt></ruby>き', stemKana:"いき", masur:'<ruby>行<rt>い</rt></ruby>きます', rule:"u-Verb: く → き"},
|
||||
{jpr:'<ruby>働<rt>はたら</rt></ruby>く', de:"arbeiten", group:"Gruppe 1 (u-Verb)", stemr:'<ruby>働<rt>はたら</rt></ruby>き', stemKana:"はたらき", masur:'<ruby>働<rt>はたら</rt></ruby>きます', rule:"u-Verb: く → き"},
|
||||
{jpr:'<ruby>話<rt>はな</rt></ruby>す', de:"sprechen", group:"Gruppe 1 (u-Verb)", stemr:'<ruby>話<rt>はな</rt></ruby>し', stemKana:"はなし", masur:'<ruby>話<rt>はな</rt></ruby>します', rule:"u-Verb: す → し"},
|
||||
{jpr:'<ruby>買<rt>か</rt></ruby>う', de:"kaufen", group:"Gruppe 1 (u-Verb)", stemr:'<ruby>買<rt>か</rt></ruby>い', stemKana:"かい", masur:'<ruby>買<rt>か</rt></ruby>います', rule:"u-Verb: う → い"},
|
||||
{jpr:'<ruby>帰<rt>かえ</rt></ruby>る', de:"heimgehen", group:"Gruppe 1 (Ausnahme!)", stemr:'<ruby>帰<rt>かえ</rt></ruby>り', stemKana:"かえり", masur:'<ruby>帰<rt>かえ</rt></ruby>ります', rule:"Sieht aus wie ru-Verb, ist aber u-Verb: る → り"},
|
||||
{jpr:'<ruby>掃除<rt>そうじ</rt></ruby>する', de:"putzen", group:"Gruppe 3 (suru)", stemr:'<ruby>掃除<rt>そうじ</rt></ruby>し', stemKana:"そうじし", masur:'<ruby>掃除<rt>そうじ</rt></ruby>します', rule:"する-Verb: する → し"},
|
||||
];
|
||||
|
||||
const SENTENCES = [
|
||||
{de:"Ich gehe nach Yokohama, um Ramen zu essen.", en:"I'll go to Yokohama to eat ramen.",
|
||||
r:'<ruby>横浜<rt>よこはま</rt></ruby><span class="p-ni">に</span> ラーメン<span class="p-wo">を</span> <ruby>食<rt>た</rt></ruby>べ<span class="p-ni">に</span> <ruby>行<rt>い</rt></ruby>きます。',
|
||||
read:"よこはまに らーめんを たべに いきます。"},
|
||||
{de:"Ich gehe nach Kyoto, um Matcha zu trinken.", en:"I'll go to Kyoto to drink matcha.",
|
||||
r:'<ruby>京都<rt>きょうと</rt></ruby><span class="p-ni">に</span> <ruby>抹茶<rt>まっちゃ</rt></ruby><span class="p-wo">を</span> <ruby>飲<rt>の</rt></ruby>み<span class="p-ni">に</span> <ruby>行<rt>い</rt></ruby>きます。',
|
||||
read:"きょうとに まっちゃを のみに いきます。"},
|
||||
{de:"Gehst du (manchmal) ins Café, um Kaffee zu trinken?", en:"Do you go to a café to drink coffee?",
|
||||
r:'カフェ<span class="p-ni">に</span> コーヒー<span class="p-wo">を</span> <ruby>飲<rt>の</rt></ruby>み<span class="p-ni">に</span> いきますか。',
|
||||
read:"かふぇに こーひーを のみに いきますか。"},
|
||||
{de:"Gehst du (manchmal) ins Restaurant, um Abendessen zu essen?", en:"Do you go to a restaurant to eat dinner?",
|
||||
r:'レストラン<span class="p-ni">に</span> <ruby>晩<rt>ばん</rt></ruby>ごはん<span class="p-wo">を</span> <ruby>食<rt>た</rt></ruby>べ<span class="p-ni">に</span> いきますか。',
|
||||
read:"れすとらんに ばんごはんを たべに いきますか。"},
|
||||
{de:"Aber jeden Morgen trinke ich zu Hause Kaffee.", en:"But every morning I drink coffee at home.",
|
||||
r:'でも <ruby>毎朝<rt>まいあさ</rt></ruby> うち<span class="p-de">で</span> コーヒー<span class="p-wo">を</span> <ruby>飲<rt>の</rt></ruby>みます。',
|
||||
read:"でも まいあさ うちで こーひーを のみます。"},
|
||||
{de:"Aber jeden Abend koche ich zu Hause das Abendessen.", en:"But every night I make dinner at home.",
|
||||
r:'でも <ruby>毎晩<rt>まいばん</rt></ruby> うち<span class="p-de">で</span> <ruby>晩<rt>ばん</rt></ruby>ごはん<span class="p-wo">を</span> <ruby>作<rt>つく</rt></ruby>ります。',
|
||||
read:"でも まいばん うちで ばんごはんを つくります。"},
|
||||
{de:"Was hast du gestern gemacht?", en:"What did you do yesterday?",
|
||||
r:'<ruby>昨日<rt>きのう</rt></ruby> <ruby>何<rt>なに</rt></ruby><span class="p-wo">を</span> しましたか。',
|
||||
read:"きのう なにを しましたか。"},
|
||||
{de:"Ich bin zur Arbeit gegangen und habe gearbeitet.", en:"I went to work and worked.",
|
||||
r:'<ruby>仕事<rt>しごと</rt></ruby><span class="p-ni">に</span> <ruby>行<rt>い</rt></ruby>って <ruby>働<rt>はたら</rt></ruby>きました。',
|
||||
read:"しごとに いって はたらきました。"},
|
||||
{de:"Dann habe ich den Keller sauber geputzt.", en:"Then I cleaned the basement.",
|
||||
r:'そして <ruby>地下室<rt>ちかしつ</rt></ruby><span class="p-wo">を</span> そうじしました。',
|
||||
read:"そして ちかしつを そうじしました。"},
|
||||
];
|
||||
|
||||
const PHRASES = [
|
||||
{jpr:'お<ruby>願<rt>ねが</rt></ruby>いします。', read:"おねがいします", de:"Bitte. (allgemeine Bitte)"},
|
||||
{jpr:'よろしくお<ruby>願<rt>ねが</rt></ruby>いします。', read:"よろしくおねがいします", de:"Bitte um gute Zusammenarbeit (zu Beginn)."},
|
||||
{jpr:'もう<ruby>一度<rt>いちど</rt></ruby>お<ruby>願<rt>ねが</rt></ruby>いします。', read:"もういちどおねがいします", de:"Noch einmal, bitte."},
|
||||
{jpr:'ゆっくりお<ruby>願<rt>ねが</rt></ruby>いします。', read:"ゆっくりおねがいします", de:"Langsamer, bitte."},
|
||||
{jpr:'もう<ruby>少<rt>すこ</rt></ruby>しゆっくり<ruby>話<rt>はな</rt></ruby>してください。', read:"もうすこしゆっくりはなしてください", de:"Bitte sprich etwas langsamer."},
|
||||
{jpr:'すみません、わかりません。', read:"すみません、わかりません", de:"Entschuldigung, ich verstehe nicht."},
|
||||
{jpr:'わかりました。', read:"わかりました", de:"Ich habe verstanden."},
|
||||
{jpr:'〜は<ruby>日本語<rt>にほんご</rt></ruby>で<ruby>何<rt>なん</rt></ruby>ですか。', read:"〜はにほんごでなんですか", de:"Wie heißt … auf Japanisch?"},
|
||||
{jpr:'〜はどういう<ruby>意味<rt>いみ</rt></ruby>ですか。', read:"〜はどういういみですか", de:"Was bedeutet …?"},
|
||||
{jpr:'これはどう<ruby>読<rt>よ</rt></ruby>みますか。', read:"これはどうよみますか", de:"Wie liest man das?"},
|
||||
{jpr:'<ruby>質問<rt>しつもん</rt></ruby>があります。', read:"しつもんがあります", de:"Ich habe eine Frage."},
|
||||
{jpr:'もう<ruby>一度<rt>いちど</rt></ruby><ruby>言<rt>い</rt></ruby>ってください。', read:"もういちどいってください", de:"Bitte sag es noch einmal."},
|
||||
{jpr:'<ruby>例<rt>れい</rt></ruby>をお<ruby>願<rt>ねが</rt></ruby>いします。', read:"れいをおねがいします", de:"Ein Beispiel, bitte."},
|
||||
{jpr:'ちょっと<ruby>待<rt>ま</rt></ruby>ってください。', read:"ちょっとまってください", de:"Einen Moment, bitte."},
|
||||
{jpr:'<ruby>大丈夫<rt>だいじょうぶ</rt></ruby>です。', read:"だいじょうぶです", de:"Alles gut / passt."},
|
||||
{jpr:'<ruby>宿題<rt>しゅくだい</rt></ruby>は<ruby>何<rt>なん</rt></ruby>ですか。', read:"しゅくだいはなんですか", de:"Was ist die Hausaufgabe?"},
|
||||
{jpr:'ありがとうございました。', read:"ありがとうございました", de:"Vielen Dank! (am Ende)"},
|
||||
{jpr:'また<ruby>来週<rt>らいしゅう</rt></ruby>。', read:"またらいしゅう", de:"Bis nächste Woche."},
|
||||
{jpr:'ヒントおねがいします。', read:"ひんとおねがいします", de:"Bitte gib mir einen Tipp."},
|
||||
{jpr:'〜は<ruby>何<rt>なん</rt></ruby>でしたっけ。', read:"〜はなんでしたっけ", de:"Wie war … noch mal?"},
|
||||
];
|
||||
|
||||
const PARTICLES = [
|
||||
{parts:['<ruby>横浜<rt>よこはま</rt></ruby>',"___","ラーメン","___",'<ruby>食<rt>た</rt></ruby>べ',"___",'<ruby>行<rt>い</rt></ruby>きます。'], ans:["に","を","に"], hint:"nach Yokohama, um Ramen zu essen"},
|
||||
{parts:["カフェ","___","コーヒー","___",'<ruby>飲<rt>の</rt></ruby>み',"___","いきます。"], ans:["に","を","に"], hint:"ins Café, um Kaffee zu trinken"},
|
||||
{parts:['まいあさ うち',"___","コーヒー","___",'<ruby>飲<rt>の</rt></ruby>みます。'], ans:["で","を"], hint:"Ort der Handlung, nicht Ziel!"},
|
||||
{parts:['<ruby>京都<rt>きょうと</rt></ruby>',"___",'<ruby>抹茶<rt>まっちゃ</rt></ruby>',"___",'<ruby>飲<rt>の</rt></ruby>み',"___",'<ruby>行<rt>い</rt></ruby>きます。'], ans:["に","を","に"], hint:"nach Kyoto, um Matcha zu trinken"},
|
||||
{parts:['<ruby>仕事<rt>しごと</rt></ruby>',"___",'<ruby>行<rt>い</rt></ruby>って <ruby>働<rt>はたら</rt></ruby>きました。'], ans:["に"], hint:"zur Arbeit gehen"},
|
||||
{parts:['<ruby>地下室<rt>ちかしつ</rt></ruby>',"___","そうじしました。"], ans:["を"], hint:"das Objekt, das geputzt wird"},
|
||||
];
|
||||
const CHOICES = ["に","を","で","は","か"];
|
||||
|
||||
/* ================= LEKTIONEN (hier hängt Kody-san neue Lektionen an) ================= */
|
||||
const LESSONS = [
|
||||
/* ---------- CM_1-2 Question Sentences ---------- */
|
||||
{id:'cm1-2', code:'CM_1-2', title:'Question Sentences',
|
||||
grammar:'Fragen mit <b>~ですか</b> beantworten: <b>はい、そうです。</b> (ja) / <b>いいえ、ちがいます。</b> (nein).',
|
||||
vocab:[
|
||||
{jpr:'そうです', read:"そうです", de:"genau / so ist es", en:"that's right", kana:"そうです"},
|
||||
{jpr:'ちがう', read:"ちがう(ちがいます)", de:"falsch / anders sein", en:"to be wrong", kana:"ちがう"},
|
||||
{jpr:'<ruby>学生<rt>がくせい</rt></ruby>', read:"がくせい", de:"Student", en:"student", kana:"がくせい"},
|
||||
{jpr:'エンジニア', read:"えんじにあ", de:"Ingenieur", en:"engineer", kana:"えんじにあ"},
|
||||
{jpr:'はい', read:"はい", de:"ja", en:"yes", kana:"はい"},
|
||||
{jpr:'いいえ', read:"いいえ", de:"nein", en:"no", kana:"いいえ"},
|
||||
],
|
||||
verbs:[],
|
||||
sentences:[
|
||||
{de:"Bist du DevOps-Engineer?", en:"Are you a DevOps engineer?", r:'Dさん<span class="p-wa">は</span> DevOps エンジニアですか。', read:"Dさんは DevOps えんじにあですか。"},
|
||||
{de:"Ja, das stimmt.", en:"Yes, it is.", r:'はい、そうです。', read:"はい、そうです。"},
|
||||
{de:"Bist du Student?", en:"Are you a student?", r:'Dさん<span class="p-wa">は</span> <ruby>学生<rt>がくせい</rt></ruby>ですか。', read:"Dさんは がくせいですか。"},
|
||||
{de:"Nein, ich bin kein Student.", en:"No, I'm not a student.", r:'いいえ、<ruby>学生<rt>がくせい</rt></ruby>じゃないです。', read:"いいえ、がくせいじゃないです。"},
|
||||
{de:"Nein, das stimmt nicht.", en:"No, that's not right.", r:'いいえ、ちがいます。', read:"いいえ、ちがいます。"},
|
||||
],
|
||||
particles:[
|
||||
{parts:['Dさん',"___",'<ruby>学生<rt>がくせい</rt></ruby>ですか。'], ans:["は"], hint:"Themenpartikel"},
|
||||
]},
|
||||
|
||||
/* ---------- CM_3-6 Frequency Adverbs ---------- */
|
||||
{id:'cm3-6', code:'CM_3-6', title:'Frequency Adverbs',
|
||||
grammar:'Häufigkeit: <b>ときどき</b> (manchmal) + V<b>ます</b> · <b>あんまり/あまり</b> (nicht sehr) + V<b>ません</b>.',
|
||||
vocab:[
|
||||
{jpr:'ときどき', read:"ときどき", de:"manchmal", en:"sometimes", kana:"ときどき"},
|
||||
{jpr:'あんまり', read:"あんまり(あまり)", de:"nicht besonders", en:"not very", kana:"あんまり"},
|
||||
{jpr:'ジム', read:"じむ", de:"Fitnessstudio", en:"gym", kana:"じむ"},
|
||||
{jpr:'カレー', read:"かれー", de:"Curry", en:"curry", kana:"かれー"},
|
||||
{jpr:'からい', read:"からい", de:"scharf", en:"spicy", kana:"からい"},
|
||||
{jpr:'<ruby>食<rt>た</rt></ruby>べ<ruby>物<rt>もの</rt></ruby>', read:"たべもの", de:"Essen / Speise", en:"food", kana:"たべもの"},
|
||||
{jpr:'<ruby>卵<rt>たまご</rt></ruby>', read:"たまご", de:"Ei", en:"egg", kana:"たまご"},
|
||||
{jpr:'じゃがいも', read:"じゃがいも", de:"Kartoffel", en:"potato", kana:"じゃがいも"},
|
||||
{jpr:'<ruby>塩<rt>しお</rt></ruby>', read:"しお", de:"Salz", en:"salt", kana:"しお"},
|
||||
{jpr:'<ruby>料理<rt>りょうり</rt></ruby>', read:"りょうり", de:"Gericht / Küche", en:"dish, cooking", kana:"りょうり"},
|
||||
{jpr:'ビール', read:"びーる", de:"Bier", en:"beer", kana:"びーる"},
|
||||
{jpr:'<ruby>高<rt>たか</rt></ruby>い', read:"たかい", de:"teuer / hoch", en:"expensive", kana:"たかい"},
|
||||
{jpr:'<ruby>好<rt>す</rt></ruby>き', read:"すき", de:"mögen", en:"to like", kana:"すき"},
|
||||
],
|
||||
verbs:[],
|
||||
sentences:[
|
||||
{de:"Ich gehe manchmal ins Fitnessstudio.", en:"I sometimes go to the gym.", r:'(わたし<span class="p-wa">は</span>)ときどき ジム<span class="p-ni">に</span> いきます。', read:"わたしは ときどき じむに いきます。"},
|
||||
{de:"Isst du manchmal japanisches Essen?", en:"Do you sometimes eat Japanese food?", r:'Dさん<span class="p-wa">は</span> ときどき <ruby>日本<rt>にほん</rt></ruby>の <ruby>食<rt>た</rt></ruby>べ<ruby>物<rt>もの</rt></ruby><span class="p-wo">を</span> <ruby>食<rt>た</rt></ruby>べますか。', read:"Dさんは ときどき にほんの たべものを たべますか。"},
|
||||
{de:"Ja, manchmal esse ich Curry.", en:"Yes, I sometimes eat curry.", r:'はい。ときどき カレー<span class="p-wo">を</span> <ruby>食<rt>た</rt></ruby>べます。', read:"はい。ときどき かれーを たべます。"},
|
||||
{de:"Magst du scharfes Essen?", en:"Do you like spicy food?", r:'からい <ruby>食<rt>た</rt></ruby>べ<ruby>物<rt>もの</rt></ruby><span class="p-ga">が</span> <ruby>好<rt>す</rt></ruby>きですか。', read:"からい たべものが すきですか。"},
|
||||
{de:"Ich gehe nicht oft ins Fitnessstudio.", en:"I don't go to the gym very often.", r:'(わたし<span class="p-wa">は</span>)あんまり ジム<span class="p-ni">に</span> いきません。', read:"わたしは あんまり じむに いきません。"},
|
||||
{de:"Ich mag Bier, aber ich trinke nicht viel.", en:"I like beer, but I don't drink much.", r:'ビール<span class="p-ga">が</span> <ruby>好<rt>す</rt></ruby>きです。でも あんまり <ruby>飲<rt>の</rt></ruby>みません。', read:"びーるが すきです。でも あんまり のみません。"},
|
||||
],
|
||||
particles:[
|
||||
{parts:['ときどき ジム',"___",'いきます。'], ans:["に"], hint:"Bewegungsziel"},
|
||||
{parts:['カレー',"___",'<ruby>食<rt>た</rt></ruby>べます。'], ans:["を"], hint:"Objekt"},
|
||||
{parts:['からい <ruby>食<rt>た</rt></ruby>べ<ruby>物<rt>もの</rt></ruby>',"___",'<ruby>好<rt>す</rt></ruby>きです。'], ans:["が"], hint:"bei 好き steht が"},
|
||||
{parts:['あんまり ジム',"___",'いきません。'], ans:["に"], hint:"Bewegungsziel"},
|
||||
]},
|
||||
|
||||
/* ---------- CM_4-1 X があります ---------- */
|
||||
{id:'cm4-1', code:'CM_4-1', title:'X があります (There is X)',
|
||||
grammar:'<b>{Ort に}{Nomen が}{あります}</b> für Dinge · <b>{います}</b> für Lebewesen.',
|
||||
vocab:[
|
||||
{jpr:'<ruby>屋<rt>や</rt></ruby>', read:"や", de:"…-Laden (Suffix)", en:"shop", kana:"や"},
|
||||
{jpr:'ラーメン<ruby>屋<rt>や</rt></ruby>', read:"らーめんや", de:"Ramen-Laden", en:"ramen shop", kana:"らーめんや"},
|
||||
{jpr:'お<ruby>城<rt>しろ</rt></ruby>', read:"おしろ", de:"Burg / Schloss", en:"castle", kana:"おしろ"},
|
||||
{jpr:'<ruby>町<rt>まち</rt></ruby>', read:"まち", de:"Stadt", en:"town", kana:"まち"},
|
||||
{jpr:'<ruby>日本人<rt>にほんじん</rt></ruby>', read:"にほんじん", de:"Japaner", en:"Japanese person", kana:"にほんじん"},
|
||||
{jpr:'たくさん', read:"たくさん", de:"viele / viel", en:"a lot", kana:"たくさん"},
|
||||
{jpr:'ある', read:"ある(あります)", de:"es gibt (Dinge)", en:"there is (things)", kana:"ある"},
|
||||
{jpr:'いる', read:"いる(います)", de:"es gibt (Lebewesen)", en:"there is (living)", kana:"いる"},
|
||||
],
|
||||
verbs:[],
|
||||
sentences:[
|
||||
{de:"In Yokohama gibt es einen Ramen-Laden.", en:"There is a ramen shop in Yokohama.", r:'<ruby>横浜<rt>よこはま</rt></ruby><span class="p-ni">に</span> ラーメン<ruby>屋<rt>や</rt></ruby><span class="p-ga">が</span> あります。', read:"よこはまに らーめんやが あります。"},
|
||||
{de:"In Osaka gibt es eine Burg.", en:"There is a castle in Osaka.", r:'<ruby>大阪<rt>おおさか</rt></ruby><span class="p-ni">に</span> お<ruby>城<rt>しろ</rt></ruby><span class="p-ga">が</span> あります。', read:"おおさかに おしろが あります。"},
|
||||
{de:"Auch in Deutschland gibt es Burgen.", en:"There are castles in Germany too.", r:'ドイツ<span class="p-ni">に</span>も お<ruby>城<rt>しろ</rt></ruby><span class="p-ga">が</span> あります。', read:"どいつにも おしろが あります。"},
|
||||
{de:"Ja, es gibt viele Burgen.", en:"Yes, there are a lot of castles.", r:'はい。たくさん お<ruby>城<rt>しろ</rt></ruby><span class="p-ga">が</span> あります。', read:"はい。たくさん おしろが あります。"},
|
||||
{de:"In meiner Stadt gibt es Japaner.", en:"There are Japanese people in my city.", r:'<ruby>私<rt>わたし</rt></ruby>の<ruby>町<rt>まち</rt></ruby><span class="p-ni">に</span> <ruby>日本人<rt>にほんじん</rt></ruby><span class="p-ga">が</span> います。', read:"わたしのまちに にほんじんが います。"},
|
||||
],
|
||||
particles:[
|
||||
{parts:['<ruby>横浜<rt>よこはま</rt></ruby>',"___",'ラーメン<ruby>屋<rt>や</rt></ruby>',"___",'あります。'], ans:["に","が"], hint:"Ort に … が あります"},
|
||||
{parts:['<ruby>大阪<rt>おおさか</rt></ruby>',"___",'お<ruby>城<rt>しろ</rt></ruby>',"___",'あります。'], ans:["に","が"], hint:"Ort に … が あります"},
|
||||
{parts:['<ruby>私<rt>わたし</rt></ruby>の<ruby>町<rt>まち</rt></ruby>',"___",'<ruby>日本人<rt>にほんじん</rt></ruby>',"___",'います。'], ans:["に","が"], hint:"Lebewesen → います"},
|
||||
]},
|
||||
|
||||
/* ---------- CM_7-3 noun1 は noun2 が adj です ---------- */
|
||||
{id:'cm7-3', code:'CM_7-3', title:'noun1 は noun2 が adj です',
|
||||
grammar:'<b>{Nomen1 は}{Nomen2 が}{Adjektiv です}</b> — etwas anhand eines Merkmals beschreiben (Ort/Können/Eigenschaft).',
|
||||
vocab:[
|
||||
{jpr:'おいしい', read:"おいしい", de:"lecker", en:"delicious", kana:"おいしい"},
|
||||
{jpr:'<ruby>有名<rt>ゆうめい</rt></ruby>', read:"ゆうめい", de:"berühmt", en:"famous", kana:"ゆうめい"},
|
||||
{jpr:'お<ruby>寺<rt>てら</rt></ruby>', read:"おてら", de:"Tempel", en:"temple", kana:"おてら"},
|
||||
{jpr:'<ruby>上手<rt>じょうず</rt></ruby>', read:"じょうず", de:"gut können", en:"good at", kana:"じょうず"},
|
||||
{jpr:'<ruby>友達<rt>ともだち</rt></ruby>', read:"ともだち", de:"Freund", en:"friend", kana:"ともだち"},
|
||||
{jpr:'<ruby>日本語<rt>にほんご</rt></ruby>', read:"にほんご", de:"Japanisch", en:"Japanese (language)", kana:"にほんご"},
|
||||
{jpr:'みそラーメン', read:"みそらーめん", de:"Miso-Ramen", en:"miso ramen", kana:"みそらーめん"},
|
||||
{jpr:'<ruby>船<rt>ふね</rt></ruby>', read:"ふね", de:"Schiff", en:"ship", kana:"ふね"},
|
||||
{jpr:'<ruby>妹<rt>いもうと</rt></ruby>', read:"いもうと", de:"jüngere Schwester", en:"younger sister", kana:"いもうと"},
|
||||
{jpr:'ゲーム', read:"げーむ", de:"Spiel", en:"game", kana:"げーむ"},
|
||||
],
|
||||
verbs:[],
|
||||
sentences:[
|
||||
{de:"Bei Ippudo ist der Miso-Ramen lecker.", en:"As for Ippudo, its miso ramen is delicious.", r:'<ruby>一風堂<rt>いっぷうどう</rt></ruby><span class="p-wa">は</span> みそラーメン<span class="p-ga">が</span> おいしいです。', read:"いっぷうどうは みそらーめんが おいしいです。"},
|
||||
{de:"Bei Coco Ichi ist das Curry lecker.", en:"As for CoCo Ichi, its curry is delicious.", r:'ココイチ<span class="p-wa">は</span> カレー<span class="p-ga">が</span> おいしいです。', read:"ここいちは かれーが おいしいです。"},
|
||||
{de:"Kyoto ist berühmt für seine Tempel.", en:"As for Kyoto, its temples are famous.", r:'<ruby>京都<rt>きょうと</rt></ruby><span class="p-wa">は</span> お<ruby>寺<rt>てら</rt></ruby><span class="p-ga">が</span> <ruby>有名<rt>ゆうめい</rt></ruby>です。', read:"きょうとは おてらが ゆうめいです。"},
|
||||
{de:"Flensburg ist berühmt für seine Schiffe.", en:"As for Flensburg, its ships are famous.", r:'フレンスブルク<span class="p-wa">は</span> <ruby>船<rt>ふね</rt></ruby><span class="p-ga">が</span> <ruby>有名<rt>ゆうめい</rt></ruby>です。', read:"ふれんすぶるくは ふねが ゆうめいです。"},
|
||||
{de:"Mein Freund ist gut in Japanisch.", en:"As for my friend, they're good at Japanese.", r:'<ruby>私<rt>わたし</rt></ruby>の<ruby>友達<rt>ともだち</rt></ruby><span class="p-wa">は</span> <ruby>日本語<rt>にほんご</rt></ruby><span class="p-ga">が</span> <ruby>上手<rt>じょうず</rt></ruby>です。', read:"わたしのともだちは にほんごが じょうずです。"},
|
||||
{de:"Meine Schwester ist gut in Videospielen.", en:"My sister is good at games.", r:'<ruby>私<rt>わたし</rt></ruby>の<ruby>妹<rt>いもうと</rt></ruby><span class="p-wa">は</span> ゲーム<span class="p-ga">が</span> <ruby>上手<rt>じょうず</rt></ruby>です。', read:"わたしのいもうとは げーむが じょうずです。"},
|
||||
],
|
||||
particles:[
|
||||
{parts:['<ruby>一風堂<rt>いっぷうどう</rt></ruby>',"___",'みそラーメン',"___",'おいしいです。'], ans:["は","が"], hint:"Thema は … Merkmal が"},
|
||||
{parts:['<ruby>京都<rt>きょうと</rt></ruby>',"___",'お<ruby>寺<rt>てら</rt></ruby>',"___",'<ruby>有名<rt>ゆうめい</rt></ruby>です。'], ans:["は","が"], hint:"Thema は … Merkmal が"},
|
||||
{parts:['<ruby>友達<rt>ともだち</rt></ruby>',"___",'<ruby>日本語<rt>にほんご</rt></ruby>',"___",'<ruby>上手<rt>じょうず</rt></ruby>です。'], ans:["は","が"], hint:"bei 上手 steht が"},
|
||||
]},
|
||||
|
||||
/* ---------- CM_7-5 The Purpose of Movement (bestehend – IDs unverändert) ---------- */
|
||||
{id:'cm7-5', code:'CM_7-5', title:'The Purpose of Movement',
|
||||
grammar:'<b>{Ziel に}{Nomen を}{V ますStamm に}{いきます}</b> — irgendwohin gehen, <b>um</b> etwas zu tun. Gegensatz: <b>~で</b> = Ort einer Handlung.',
|
||||
vocab:VOCAB, verbs:VERBS, sentences:SENTENCES, particles:PARTICLES},
|
||||
|
||||
/* ---------- CM_11-3 ~ことがあります ---------- */
|
||||
{id:'cm11-3', code:'CM_11-3', title:'~ことがあります (Erfahrung)',
|
||||
grammar:'<b>{V た-Form}{ことが}{あります}</b> — „schon mal … getan haben". <b>こと</b> macht aus dem Verb ein Nomen; た-Form nötig (いく→いった).',
|
||||
vocab:[
|
||||
{jpr:'こと', read:"こと", de:"(Nominalisierer)", en:"noun-maker", kana:"こと"},
|
||||
{jpr:'<ruby>北海道<rt>ほっかいどう</rt></ruby>', read:"ほっかいどう", de:"Hokkaido", en:"Hokkaido", kana:"ほっかいどう"},
|
||||
{jpr:'そば', read:"そば", de:"Soba(-Nudeln)", en:"soba", kana:"そば"},
|
||||
{jpr:'<ruby>金沢<rt>かなざわ</rt></ruby>', read:"かなざわ", de:"Kanazawa", en:"Kanazawa", kana:"かなざわ"},
|
||||
{jpr:'<ruby>行<rt>い</rt></ruby>った', read:"いった", de:"gegangen (た-Form)", en:"went", kana:"いった"},
|
||||
{jpr:'<ruby>食<rt>た</rt></ruby>べた', read:"たべた", de:"gegessen (た-Form)", en:"ate", kana:"たべた"},
|
||||
{jpr:'デンマーク', read:"でんまーく", de:"Dänemark", en:"Denmark", kana:"でんまーく"},
|
||||
],
|
||||
verbs:[],
|
||||
sentences:[
|
||||
{de:"Ich war schon mal in Japan.", en:"I have been to Japan.", r:'<ruby>日本<rt>にほん</rt></ruby><span class="p-ni">に</span> <ruby>行<rt>い</rt></ruby>った こと<span class="p-ga">が</span> あります。', read:"にほんに いった ことが あります。"},
|
||||
{de:"Ich war schon mal in Osaka.", en:"I have been to Osaka.", r:'<ruby>大阪<rt>おおさか</rt></ruby><span class="p-ni">に</span> <ruby>行<rt>い</rt></ruby>った こと<span class="p-ga">が</span> あります。', read:"おおさかに いった ことが あります。"},
|
||||
{de:"Warst du schon mal in Hokkaido? — Nein, noch nie.", en:"Have you been to Hokkaido? — No, I haven't.", r:'<ruby>北海道<rt>ほっかいどう</rt></ruby><span class="p-ni">に</span> <ruby>行<rt>い</rt></ruby>った こと<span class="p-ga">が</span> ありますか。いえ。ありません。', read:"ほっかいどうに いった ことが ありますか。いえ。ありません。"},
|
||||
{de:"Ich habe schon mal Ramen gegessen.", en:"I have eaten ramen.", r:'ラーメン<span class="p-wo">を</span> <ruby>食<rt>た</rt></ruby>べた こと<span class="p-ga">が</span> あります。', read:"らーめんを たべた ことが あります。"},
|
||||
{de:"Wo hast du es gegessen? — In Kanazawa.", en:"Where did you eat it? — In Kanazawa.", r:'どこ<span class="p-de">で</span> <ruby>食<rt>た</rt></ruby>べましたか。かなざわ<span class="p-de">で</span> <ruby>食<rt>た</rt></ruby>べました。', read:"どこで たべましたか。かなざわで たべました。"},
|
||||
],
|
||||
particles:[
|
||||
{parts:['<ruby>日本<rt>にほん</rt></ruby>',"___",'<ruby>行<rt>い</rt></ruby>った こと',"___",'あります。'], ans:["に","が"], hint:"Ziel に … こと が"},
|
||||
{parts:['ラーメン',"___",'<ruby>食<rt>た</rt></ruby>べた こと',"___",'あります。'], ans:["を","が"], hint:"Objekt を … こと が"},
|
||||
{parts:['どこ',"___",'<ruby>食<rt>た</rt></ruby>べましたか。'], ans:["で"], hint:"Ort der Handlung"},
|
||||
]},
|
||||
|
||||
/* ---------- CM_20-5 Name という Item ---------- */
|
||||
{id:'cm20-5', code:'CM_20-5', title:'Name という Item',
|
||||
grammar:'<b>{Nomen}{という}{Nomen2}</b> — „ein …(Nomen2) <b>namens</b> …(Nomen)".',
|
||||
vocab:[
|
||||
{jpr:'という', read:"という", de:"genannt / namens", en:"called, named", kana:"という"},
|
||||
{jpr:'<ruby>一風堂<rt>いっぷうどう</rt></ruby>', read:"いっぷうどう", de:"Ippudo (Ramen-Kette)", en:"Ippudo", kana:"いっぷうどう"},
|
||||
{jpr:'カレー<ruby>屋<rt>や</rt></ruby>', read:"かれーや", de:"Curry-Laden", en:"curry shop", kana:"かれーや"},
|
||||
{jpr:'たこ<ruby>焼<rt>や</rt></ruby>き', read:"たこやき", de:"Takoyaki", en:"takoyaki", kana:"たこやき"},
|
||||
{jpr:'ラーメン<ruby>屋<rt>や</rt></ruby>', read:"らーめんや", de:"Ramen-Laden", en:"ramen shop", kana:"らーめんや"},
|
||||
],
|
||||
verbs:[],
|
||||
sentences:[
|
||||
{de:"Ich war in einem Ramen-Laden namens Ippudo.", en:"I went to a ramen shop called Ippudo.", r:'<ruby>一風堂<rt>いっぷうどう</rt></ruby>という ラーメン<ruby>屋<rt>や</rt></ruby><span class="p-ni">に</span> <ruby>行<rt>い</rt></ruby>きました。', read:"いっぷうどうという らーめんやに いきました。"},
|
||||
{de:"Ich war in einem Curry-Laden namens Cocos Curry.", en:"I went to a curry shop called Cocos Curry.", r:'ココスカレーという カレー<ruby>屋<rt>や</rt></ruby><span class="p-ni">に</span> <ruby>行<rt>い</rt></ruby>きました。', read:"ここすかれーという かれーやに いきました。"},
|
||||
{de:"Ich habe ein Gericht namens Takoyaki gegessen.", en:"I ate a food called takoyaki.", r:'たこ<ruby>焼<rt>や</rt></ruby>きという <ruby>食<rt>た</rt></ruby>べ<ruby>物<rt>もの</rt></ruby><span class="p-wo">を</span> <ruby>食<rt>た</rt></ruby>べました。', read:"たこやきという たべものを たべました。"},
|
||||
],
|
||||
particles:[
|
||||
{parts:['<ruby>一風堂<rt>いっぷうどう</rt></ruby>という ラーメン<ruby>屋<rt>や</rt></ruby>',"___",'<ruby>行<rt>い</rt></ruby>きました。'], ans:["に"], hint:"Bewegungsziel"},
|
||||
{parts:['たこ<ruby>焼<rt>や</rt></ruby>きという <ruby>食<rt>た</rt></ruby>べ<ruby>物<rt>もの</rt></ruby>',"___",'<ruby>食<rt>た</rt></ruby>べました。'], ans:["を"], hint:"Objekt"},
|
||||
]},
|
||||
|
||||
/* ---------- SP_Degree Adverb (crazy) めっちゃ ---------- */
|
||||
{id:'sp-meccha', code:'SP_めっちゃ', title:'Degree Adverb (crazy)',
|
||||
grammar:'<b>{Nomen は}{めっちゃ}{Adjektiv です}</b> — めっちゃ = „extrem/voll" (locker, gesprochen; stärker/emotionaler als とても).',
|
||||
vocab:[
|
||||
{jpr:'めっちゃ', read:"めっちゃ", de:"extrem / voll (locker)", en:"extremely (casual)", kana:"めっちゃ"},
|
||||
{jpr:'<ruby>甘<rt>あま</rt></ruby>い', read:"あまい", de:"süß", en:"sweet", kana:"あまい"},
|
||||
{jpr:'アイスクリーム', read:"あいすくりーむ", de:"Eis", en:"ice cream", kana:"あいすくりーむ"},
|
||||
{jpr:'いちご', read:"いちご", de:"Erdbeere", en:"strawberry", kana:"いちご"},
|
||||
{jpr:'とても', read:"とても", de:"sehr (neutral)", en:"very", kana:"とても"},
|
||||
],
|
||||
verbs:[],
|
||||
sentences:[
|
||||
{de:"Nakamoto ist extrem scharf!", en:"Nakamoto is crazy spicy!", r:'<ruby>仲本<rt>なかもと</rt></ruby><span class="p-wa">は</span> めっちゃ からいです!', read:"なかもとは めっちゃ からいです!"},
|
||||
{de:"Erdbeer-Eis ist extrem süß!", en:"Strawberry ice cream is crazy sweet!", r:'いちごの アイスクリーム<span class="p-wa">は</span> めっちゃ <ruby>甘<rt>あま</rt></ruby>いです!', read:"いちごの あいすくりーむは めっちゃ あまいです!"},
|
||||
],
|
||||
particles:[
|
||||
{parts:['<ruby>仲本<rt>なかもと</rt></ruby>',"___",'めっちゃ からいです。'], ans:["は"], hint:"Themenpartikel"},
|
||||
]},
|
||||
|
||||
/* ---------- SP_Degree Adverb (fairly) まあまあ ---------- */
|
||||
{id:'sp-maamaa', code:'SP_まあまあ', title:'Degree Adverb (fairly)',
|
||||
grammar:'<b>{Nomen は}{まあまあ}{Adjektiv です}</b> — „einigermaßen/mittelmäßig". <b>まあまあ</b> allein = „geht so". Bescheiden auf Lob: <b>まだまだです</b>.',
|
||||
vocab:[
|
||||
{jpr:'まあまあ', read:"まあまあ", de:"einigermaßen / geht so", en:"fairly, so-so", kana:"まあまあ"},
|
||||
{jpr:'おもしろい', read:"おもしろい", de:"interessant", en:"interesting", kana:"おもしろい"},
|
||||
{jpr:'アニメ', read:"あにめ", de:"Anime", en:"anime", kana:"あにめ"},
|
||||
{jpr:'レストラン', read:"れすとらん", de:"Restaurant", en:"restaurant", kana:"れすとらん"},
|
||||
{jpr:'まだまだです', read:"まだまだです", de:"noch ein weiter Weg (bescheiden)", en:"I still have a long way to go", kana:"まだまだです"},
|
||||
],
|
||||
verbs:[],
|
||||
sentences:[
|
||||
{de:"Dieser Ramen ist einigermaßen scharf.", en:"This ramen is fairly spicy.", r:'このラーメン<span class="p-wa">は</span> まあまあ からいです。', read:"このらーめんは まあまあ からいです。"},
|
||||
{de:"Dieser Anime ist einigermaßen interessant.", en:"This anime is fairly interesting.", r:'このアニメ<span class="p-wa">は</span> まあまあ おもしろいです。', read:"このあにめは まあまあ おもしろいです。"},
|
||||
{de:"Dieser Anime ist okay.", en:"This anime is okay.", r:'このアニメ<span class="p-wa">は</span> まあまあです。', read:"このあにめは まあまあです。"},
|
||||
{de:"Dieses Restaurant ist okay.", en:"This restaurant is okay.", r:'このレストラン<span class="p-wa">は</span> まあまあです。', read:"このれすとらんは まあまあです。"},
|
||||
{de:"Bescheidene Antwort auf Lob (‚Ach, noch lange nicht.').", en:"Response to a compliment: I still have a long way to go.", r:'まだまだです。', read:"まだまだです。"},
|
||||
],
|
||||
particles:[
|
||||
{parts:['このラーメン',"___",'まあまあ からいです。'], ans:["は"], hint:"Themenpartikel"},
|
||||
{parts:['このアニメ',"___",'まあまあです。'], ans:["は"], hint:"Themenpartikel"},
|
||||
]},
|
||||
|
||||
/* ---------- Verbgruppen (ますStamm) ---------- */
|
||||
{id:'verbs', code:'Verben', title:'Verbgruppen & ます',
|
||||
grammar:'3 Gruppen: ① <b>Ru-Verben</b> (る weg) ② <b>U-Verben</b> (u→i) ③ <b>unregelmäßig</b> (する→し, くる→き). Hier: höfliche ます-Form.',
|
||||
vocab:[
|
||||
{jpr:'<ruby>寝<rt>ね</rt></ruby>る', read:"ねる(ねます)", de:"schlafen", en:"to sleep", kana:"ねる"},
|
||||
{jpr:'<ruby>起<rt>お</rt></ruby>きる', read:"おきる(おきます)", de:"aufstehen", en:"to get up", kana:"おきる"},
|
||||
{jpr:'<ruby>読<rt>よ</rt></ruby>む', read:"よむ(よみます)", de:"lesen", en:"to read", kana:"よむ"},
|
||||
{jpr:'<ruby>聞<rt>き</rt></ruby>く', read:"きく(ききます)", de:"hören / zuhören", en:"to listen", kana:"きく"},
|
||||
{jpr:'<ruby>来<rt>く</rt></ruby>る', read:"くる(きます)", de:"kommen", en:"to come", kana:"くる"},
|
||||
{jpr:'<ruby>勉強<rt>べんきょう</rt></ruby>する', read:"べんきょうする", de:"lernen / studieren", en:"to study", kana:"べんきょうする"},
|
||||
],
|
||||
verbs:[
|
||||
{jpr:'<ruby>食<rt>た</rt></ruby>べる', de:"essen", group:"Gruppe 2 (ru-Verb)", stemr:'<ruby>食<rt>た</rt></ruby>べ', stemKana:"たべ", masur:'<ruby>食<rt>た</rt></ruby>べます', rule:"ru-Verb: る weg → たべ"},
|
||||
{jpr:'<ruby>寝<rt>ね</rt></ruby>る', de:"schlafen", group:"Gruppe 2 (ru-Verb)", stemr:'<ruby>寝<rt>ね</rt></ruby>', stemKana:"ね", masur:'<ruby>寝<rt>ね</rt></ruby>ます', rule:"ru-Verb: る weg → ね"},
|
||||
{jpr:'<ruby>見<rt>み</rt></ruby>る', de:"sehen", group:"Gruppe 2 (ru-Verb)", stemr:'<ruby>見<rt>み</rt></ruby>', stemKana:"み", masur:'<ruby>見<rt>み</rt></ruby>ます', rule:"ru-Verb: る weg → み"},
|
||||
{jpr:'<ruby>起<rt>お</rt></ruby>きる', de:"aufstehen", group:"Gruppe 2 (ru-Verb)", stemr:'<ruby>起<rt>お</rt></ruby>き', stemKana:"おき", masur:'<ruby>起<rt>お</rt></ruby>きます', rule:"ru-Verb: る weg → おき"},
|
||||
{jpr:'<ruby>飲<rt>の</rt></ruby>む', de:"trinken", group:"Gruppe 1 (u-Verb)", stemr:'<ruby>飲<rt>の</rt></ruby>み', stemKana:"のみ", masur:'<ruby>飲<rt>の</rt></ruby>みます', rule:"u-Verb: む → み"},
|
||||
{jpr:'<ruby>読<rt>よ</rt></ruby>む', de:"lesen", group:"Gruppe 1 (u-Verb)", stemr:'<ruby>読<rt>よ</rt></ruby>み', stemKana:"よみ", masur:'<ruby>読<rt>よ</rt></ruby>みます', rule:"u-Verb: む → み"},
|
||||
{jpr:'<ruby>話<rt>はな</rt></ruby>す', de:"sprechen", group:"Gruppe 1 (u-Verb)", stemr:'<ruby>話<rt>はな</rt></ruby>し', stemKana:"はなし", masur:'<ruby>話<rt>はな</rt></ruby>します', rule:"u-Verb: す → し"},
|
||||
{jpr:'<ruby>聞<rt>き</rt></ruby>く', de:"hören", group:"Gruppe 1 (u-Verb)", stemr:'<ruby>聞<rt>き</rt></ruby>き', stemKana:"きき", masur:'<ruby>聞<rt>き</rt></ruby>きます', rule:"u-Verb: く → き"},
|
||||
{jpr:'<ruby>行<rt>い</rt></ruby>く', de:"gehen", group:"Gruppe 1 (u-Verb)", stemr:'<ruby>行<rt>い</rt></ruby>き', stemKana:"いき", masur:'<ruby>行<rt>い</rt></ruby>きます', rule:"u-Verb: く → き"},
|
||||
{jpr:'<ruby>帰<rt>かえ</rt></ruby>る', de:"heimgehen", group:"Gruppe 1 (Ausnahme!)", stemr:'<ruby>帰<rt>かえ</rt></ruby>り', stemKana:"かえり", masur:'<ruby>帰<rt>かえ</rt></ruby>ります', rule:"sieht aus wie ru-Verb, ist u-Verb: る → り"},
|
||||
{jpr:'する', de:"machen / tun", group:"Gruppe 3 (unregelmäßig)", stemr:'し', stemKana:"し", masur:'します', rule:"unregelmäßig: する → し"},
|
||||
{jpr:'<ruby>勉強<rt>べんきょう</rt></ruby>する', de:"lernen", group:"Gruppe 3 (unregelmäßig)", stemr:'<ruby>勉強<rt>べんきょう</rt></ruby>し', stemKana:"べんきょうし", masur:'<ruby>勉強<rt>べんきょう</rt></ruby>します', rule:"する-Verb: する → し"},
|
||||
{jpr:'<ruby>来<rt>く</rt></ruby>る', de:"kommen", group:"Gruppe 3 (unregelmäßig)", stemr:'<ruby>来<rt>き</rt></ruby>', stemKana:"き", masur:'<ruby>来<rt>き</rt></ruby>ます', rule:"unregelmäßig: くる → き"},
|
||||
],
|
||||
sentences:[
|
||||
{de:"Ich esse Sushi. (höflich)", en:"I eat sushi.", r:'すし<span class="p-wo">を</span> <ruby>食<rt>た</rt></ruby>べます。', read:"すしを たべます。"},
|
||||
{de:"Ich sehe einen Anime. (höflich)", en:"I watch anime.", r:'アニメ<span class="p-wo">を</span> <ruby>見<rt>み</rt></ruby>ます。', read:"あにめを みます。"},
|
||||
{de:"Ich spiele ein Spiel. (höflich)", en:"I play a game.", r:'ゲーム<span class="p-wo">を</span> します。', read:"げーむを します。"},
|
||||
{de:"Mein Freund kommt nach Japan.", en:"My friend comes to Japan.", r:'<ruby>友達<rt>ともだち</rt></ruby><span class="p-ga">が</span> <ruby>日本<rt>にほん</rt></ruby><span class="p-ni">に</span> <ruby>来<rt>き</rt></ruby>ます。', read:"ともだちが にほんに きます。"},
|
||||
],
|
||||
particles:[
|
||||
{parts:['すし',"___",'<ruby>食<rt>た</rt></ruby>べます。'], ans:["を"], hint:"Objekt"},
|
||||
{parts:['ゲーム',"___",'します。'], ans:["を"], hint:"Objekt"},
|
||||
{parts:['<ruby>友達<rt>ともだち</rt></ruby>',"___",'<ruby>日本<rt>にほん</rt></ruby>',"___",'<ruby>来<rt>き</rt></ruby>ます。'], ans:["が","に"], hint:"Subjekt が … Ziel に"},
|
||||
]},
|
||||
|
||||
/* ---------- て-Form ---------- */
|
||||
{id:'teform', code:'て-Form', title:'te-form conjugations',
|
||||
grammar:'<b>Ru</b>→て · <b>う/つ/る</b>→って · <b>む/ぶ/ぬ</b>→んで · <b>く</b>→いて (<b>行く→行って</b>!) · <b>ぐ</b>→いで · <b>す</b>→して · する→して, くる→きて.',
|
||||
vocab:[
|
||||
{jpr:'<ruby>会<rt>あ</rt></ruby>う', read:"あう", de:"(sich) treffen", en:"to meet", kana:"あう"},
|
||||
{jpr:'<ruby>待<rt>ま</rt></ruby>つ', read:"まつ", de:"warten", en:"to wait", kana:"まつ"},
|
||||
{jpr:'<ruby>遊<rt>あそ</rt></ruby>ぶ', read:"あそぶ", de:"spielen / sich vergnügen", en:"to play", kana:"あそぶ"},
|
||||
{jpr:'<ruby>泳<rt>およ</rt></ruby>ぐ', read:"およぐ", de:"schwimmen", en:"to swim", kana:"およぐ"},
|
||||
{jpr:'<ruby>書<rt>か</rt></ruby>く', read:"かく", de:"schreiben", en:"to write", kana:"かく"},
|
||||
],
|
||||
verbs:[],
|
||||
sentences:[
|
||||
{de:"て-Form von 食べる (essen)? — Ru-Verb: る→て", en:"", r:'<ruby>食<rt>た</rt></ruby>べて', read:"たべて"},
|
||||
{de:"て-Form von 見る (sehen)? — Ru-Verb: る→て", en:"", r:'<ruby>見<rt>み</rt></ruby>て', read:"みて"},
|
||||
{de:"て-Form von 会う (treffen)? — う→って", en:"", r:'<ruby>会<rt>あ</rt></ruby>って', read:"あって"},
|
||||
{de:"て-Form von 待つ (warten)? — つ→って", en:"", r:'<ruby>待<rt>ま</rt></ruby>って', read:"まって"},
|
||||
{de:"て-Form von 帰る (heimgehen)? — る→って", en:"", r:'<ruby>帰<rt>かえ</rt></ruby>って', read:"かえって"},
|
||||
{de:"て-Form von 読む (lesen)? — む→んで", en:"", r:'<ruby>読<rt>よ</rt></ruby>んで', read:"よんで"},
|
||||
{de:"て-Form von 遊ぶ (spielen)? — ぶ→んで", en:"", r:'<ruby>遊<rt>あそ</rt></ruby>んで', read:"あそんで"},
|
||||
{de:"て-Form von 書く (schreiben)? — く→いて", en:"", r:'<ruby>書<rt>か</rt></ruby>いて', read:"かいて"},
|
||||
{de:"て-Form von 行く (gehen)? — AUSNAHME: →行って", en:"", r:'<ruby>行<rt>い</rt></ruby>って', read:"いって"},
|
||||
{de:"て-Form von 泳ぐ (schwimmen)? — ぐ→いで", en:"", r:'<ruby>泳<rt>およ</rt></ruby>いで', read:"およいで"},
|
||||
{de:"て-Form von 話す (sprechen)? — す→して", en:"", r:'<ruby>話<rt>はな</rt></ruby>して', read:"はなして"},
|
||||
{de:"て-Form von する (machen)? — unregelmäßig", en:"", r:'して', read:"して"},
|
||||
{de:"て-Form von 来る (kommen)? — unregelmäßig", en:"", r:'<ruby>来<rt>き</rt></ruby>て', read:"きて"},
|
||||
],
|
||||
particles:[]},
|
||||
];
|
||||
|
||||
/* ================= RŌMAJI → KANA ================= */
|
||||
const RMAP={a:'あ',i:'い',u:'う',e:'え',o:'お',
|
||||
ka:'か',ki:'き',ku:'く',ke:'け',ko:'こ',kya:'きゃ',kyu:'きゅ',kyo:'きょ',
|
||||
ga:'が',gi:'ぎ',gu:'ぐ',ge:'げ',go:'ご',gya:'ぎゃ',gyu:'ぎゅ',gyo:'ぎょ',
|
||||
sa:'さ',shi:'し',si:'し',su:'す',se:'せ',so:'そ',sha:'しゃ',shu:'しゅ',sho:'しょ',sya:'しゃ',syu:'しゅ',syo:'しょ',
|
||||
za:'ざ',ji:'じ',zi:'じ',zu:'ず',ze:'ぜ',zo:'ぞ',ja:'じゃ',ju:'じゅ',jo:'じょ',jya:'じゃ',jyu:'じゅ',jyo:'じょ',
|
||||
ta:'た',chi:'ち',ti:'ち',tsu:'つ',tu:'つ',te:'て',to:'と',cha:'ちゃ',chu:'ちゅ',cho:'ちょ',tya:'ちゃ',tyu:'ちゅ',tyo:'ちょ',
|
||||
da:'だ',di:'ぢ',du:'づ',de:'で',do:'ど',
|
||||
na:'な',ni:'に',nu:'ぬ',ne:'ね',no:'の',nya:'にゃ',nyu:'にゅ',nyo:'にょ',
|
||||
ha:'は',hi:'ひ',fu:'ふ',hu:'ふ',he:'へ',ho:'ほ',hya:'ひゃ',hyu:'ひゅ',hyo:'ひょ',
|
||||
ba:'ば',bi:'び',bu:'ぶ',be:'べ',bo:'ぼ',bya:'びゃ',byu:'びゅ',byo:'びょ',
|
||||
pa:'ぱ',pi:'ぴ',pu:'ぷ',pe:'ぺ',po:'ぽ',pya:'ぴゃ',pyu:'ぴゅ',pyo:'ぴょ',
|
||||
ma:'ま',mi:'み',mu:'む',me:'め',mo:'も',mya:'みゃ',myu:'みゅ',myo:'みょ',
|
||||
ya:'や',yu:'ゆ',yo:'よ',
|
||||
ra:'ら',ri:'り',ru:'る',re:'れ',ro:'ろ',rya:'りゃ',ryu:'りゅ',ryo:'りょ',
|
||||
wa:'わ',wo:'を',
|
||||
fa:'ふぁ',fi:'ふぃ',fe:'ふぇ',fo:'ふぉ',
|
||||
la:'ぁ',li:'ぃ',lu:'ぅ',le:'ぇ',lo:'ぉ',xa:'ぁ',xi:'ぃ',xu:'ぅ',xe:'ぇ',xo:'ぉ',
|
||||
lya:'ゃ',lyu:'ゅ',lyo:'ょ',xya:'ゃ',xyu:'ゅ',xyo:'ょ',
|
||||
ltu:'っ',xtu:'っ',ltsu:'っ',lwa:'ゎ',xwa:'ゎ',
|
||||
'-':'ー'};
|
||||
function toKana(s){
|
||||
s=(s||'').toLowerCase().replace(/\s+/g,'');
|
||||
let o='',i=0;
|
||||
while(i<s.length){
|
||||
const c=s[i];
|
||||
if((c>=''&&c<='ヿ')||c==='ー'){o+=c;i++;continue;} // schon Kana
|
||||
if(c==='t' && s[i+1]==='c' && s[i+2]==='h'){o+='っ';i++;continue;} // "tch" (matcha → まっちゃ)
|
||||
if(c===s[i+1] && 'bcdfghjkmprstwyz'.includes(c)){o+='っ';i++;continue;} // Doppelkonsonant
|
||||
if(c==='n' && s[i+1] && !'aiueoy'.includes(s[i+1])){o+='ん';i++;continue;}
|
||||
if(c==='n' && !s[i+1]){o+='ん';i++;continue;}
|
||||
let m=false;
|
||||
for(let L=3;L>=1;L--){const ch=s.substr(i,L); if(RMAP[ch]){o+=RMAP[ch];i+=L;m=true;break;}}
|
||||
if(!m){o+=c;i++;}
|
||||
}
|
||||
return o;
|
||||
}
|
||||
const norm = s => toKana(s)
|
||||
.replace(/[・、。「」!?.,\s]/g,'') // Satzzeichen weg (ー bleibt!)
|
||||
.replace(/[゠-ヺ]/g,ch=>String.fromCharCode(ch.charCodeAt(0)-96)); // Katakana → Hiragana, ー unberührt
|
||||
// Streng: kleines ぇ ≠ großes え, ー muss getippt werden (mit "-"), っ muss stehen — alles wie im Original
|
||||
|
||||
/* ================= STATISTIK / PERSISTENZ ================= */
|
||||
// Pro Karte: {box 0-5, right, wrong, last(Zeitstempel)}
|
||||
let STATS = JSON.parse(localStorage.getItem('kody_stats')||'{}');
|
||||
(function migrate(){
|
||||
// 1) ganz alten Leitner-Stand (nur Zahlen) übernehmen
|
||||
if(!Object.keys(STATS).length){
|
||||
const old=JSON.parse(localStorage.getItem('kody_leitner')||'{}');
|
||||
for(const k in old) STATS[k]={box:old[k]||0,right:0,wrong:0,last:0};
|
||||
}
|
||||
// 2) alte IDs ohne Lektions-Präfix der ersten Lektion zuordnen
|
||||
let ch=false;
|
||||
for(const k of Object.keys(STATS)){
|
||||
if(/^(v|vb|s)\d+$/.test(k)){ STATS['cm7-5:'+k]=STATS[k]; delete STATS[k]; ch=true; }
|
||||
}
|
||||
if(ch||Object.keys(STATS).length) saveStats();
|
||||
})();
|
||||
function saveStats(){ localStorage.setItem('kody_stats',JSON.stringify(STATS)); }
|
||||
function rec(id){ return STATS[id]||(STATS[id]={box:0,right:0,wrong:0,last:0}); }
|
||||
const boxOf = id => (STATS[id]&&STATS[id].box)||0;
|
||||
function bump(id,ok){
|
||||
if(!id)return; const r=rec(id);
|
||||
if(ok){ r.right++; r.box=Math.min(5,r.box+1); }
|
||||
else { r.wrong++; r.box=0; } // was schlecht lief, kommt sofort wieder nach vorne
|
||||
r.last=Date.now(); saveStats();
|
||||
}
|
||||
function boxesHtml(id){let h='<span class="boxes">';for(let k=0;k<5;k++)h+=`<i class="${k<boxOf(id)?'on':''}"></i>`;return h+'</span>';}
|
||||
function isToday(ts){ if(!ts)return false; const d=new Date(ts),n=new Date();
|
||||
return d.getFullYear()===n.getFullYear()&&d.getMonth()===n.getMonth()&&d.getDate()===n.getDate(); }
|
||||
function doneToday(id){ const r=STATS[id]; return !!(r&&isToday(r.last)); }
|
||||
|
||||
// Metadaten der Karten (für Fortschritts-Seite) – folgt der Lektionsauswahl
|
||||
function allMeta(){
|
||||
const o=[];
|
||||
lessonsActive().forEach(L=>{
|
||||
L.vocab.forEach((v,i)=>o.push({id:L.id+':v'+i, label:v.jpr+' · '+v.de, deck:'Vokabel'}));
|
||||
L.verbs.forEach((v,i)=>o.push({id:L.id+':vb'+i, label:v.jpr+' → '+v.stemr, deck:'ますStamm'}));
|
||||
L.sentences.forEach((s,i)=>o.push({id:L.id+':s'+i, label:s.de, deck:'Satz'}));
|
||||
});
|
||||
PHRASES.forEach((p,i)=>o.push({id:'p'+i, label:p.jpr, deck:'Unterricht'}));
|
||||
return o;
|
||||
}
|
||||
// Index über ALLE Lektionen (damit schwache Karten jeder Lektion gefunden werden)
|
||||
function cardIndex(){
|
||||
const m={};
|
||||
const savedLesson=lesson; lesson='all';
|
||||
[...vocabReview(),...verbItems(),...sentenceItems(),...phraseItems()].forEach(it=>m[it.id]=it);
|
||||
lesson=savedLesson;
|
||||
return m;
|
||||
}
|
||||
function weakList(){ // geübte Karten, die noch wackeln – schwächste zuerst
|
||||
return allMeta().filter(m=>{const r=STATS[m.id]; return r&&(r.right+r.wrong>0)&&(r.wrong>0||r.box<4);})
|
||||
.sort((a,b)=>{const ra=STATS[a.id],rb=STATS[b.id]; return (rb.wrong-ra.wrong)||(ra.box-rb.box);});
|
||||
}
|
||||
function weakDeck(){ const ci=cardIndex(); return weakList().map(m=>ci[m.id]).filter(Boolean); }
|
||||
|
||||
/* ================= DECK-BUILDER ================= */
|
||||
function lessonsActive(){ return lesson==='all' ? LESSONS : LESSONS.filter(l=>l.id===lesson); }
|
||||
|
||||
function vocabItems(){
|
||||
const out=[];
|
||||
lessonsActive().forEach(L=>L.vocab.forEach((v,i)=>{ const id=L.id+':v'+i;
|
||||
out.push(dir==='deJp'
|
||||
? {id, front:`<div class="de">${v.de}</div><div class="en">${v.en}</div>`,
|
||||
back:`<div class="jp">${v.jpr}</div><div class="reading">${v.read}</div>`, typeTarget:v.kana}
|
||||
: {id, front:`<div class="jp">${v.jpr}</div>`,
|
||||
back:`<div class="de">${v.de}</div><div class="reading">${v.read}</div>`, typeTarget:null});
|
||||
}));
|
||||
return out;
|
||||
}
|
||||
function vocabReview(){ // fürs Wiederholen immer DE→JP (Produktion)
|
||||
const out=[];
|
||||
lessonsActive().forEach(L=>L.vocab.forEach((v,i)=>out.push({id:L.id+':v'+i,
|
||||
front:`<div class="de">${v.de}</div><div class="en">${v.en}</div>`,
|
||||
back:`<div class="jp">${v.jpr}</div><div class="reading">${v.read}</div>`, typeTarget:v.kana})));
|
||||
return out;
|
||||
}
|
||||
function verbItems(){
|
||||
const out=[];
|
||||
lessonsActive().forEach(L=>L.verbs.forEach((v,i)=>out.push({id:L.id+':vb'+i,
|
||||
front:`<div class="jp">${v.jpr}</div><div class="en">${v.de} · ${v.group}</div><div class="q">ますStamm? (Form vor に / ます)</div>`,
|
||||
back:`<div class="jp">${v.stemr}</div><div class="reading">→ ${v.masur}</div><div class="note">${v.rule}</div>`,
|
||||
typeTarget:v.stemKana})));
|
||||
return out;
|
||||
}
|
||||
function sentenceItems(){
|
||||
const out=[];
|
||||
lessonsActive().forEach(L=>L.sentences.forEach((s,i)=>out.push({id:L.id+':s'+i,
|
||||
front:`<div class="de">${s.de}</div><div class="en">${s.en}</div>`,
|
||||
back:`<div class="jp">${s.r}</div><div class="reading">${s.read}</div>`,
|
||||
typeTarget:s.read.replace(/\s/g,'')})));
|
||||
return out;
|
||||
}
|
||||
function particleItems(){
|
||||
const out=[];
|
||||
lessonsActive().forEach(L=>L.particles.forEach((p,i)=>out.push({...p, id:L.id+':pt'+i})));
|
||||
return out;
|
||||
}
|
||||
function phraseItems(){
|
||||
return PHRASES.map((p,i)=>({id:'p'+i,
|
||||
front:`<div class="de">${p.de}</div>`,
|
||||
back:`<div class="jp">${p.jpr}</div><div class="reading">${p.read}</div>`,
|
||||
typeTarget:p.read}));
|
||||
}
|
||||
function reviewDeck(){
|
||||
const items=[...vocabReview(), ...verbItems(), ...phraseItems()];
|
||||
return items.sort((a,b)=>boxOf(a.id)-boxOf(b.id)); // schwache zuerst
|
||||
}
|
||||
|
||||
/* ================= STATE ================= */
|
||||
let mode="review", queue=[], idx=0, correct=0, total=0, sessionAll=false;
|
||||
let dir = localStorage.getItem('kody_dir')||'deJp';
|
||||
let method = localStorage.getItem('kody_method')||'self'; // 'self' | 'type'
|
||||
let lesson = localStorage.getItem('kody_lesson')||LESSONS[0].id; // Lektions-Filter oder 'all'
|
||||
if(lesson!=='all' && !LESSONS.some(l=>l.id===lesson)) lesson=LESSONS[0].id;
|
||||
const GENERIC=['review','weak','vocab','verbstem','sentence','phrases'];
|
||||
|
||||
const app=document.getElementById("app");
|
||||
const bar=document.getElementById("bar");
|
||||
const counter=document.getElementById("counter");
|
||||
const scoreEl=document.getElementById("score");
|
||||
|
||||
function shuffle(a){a=a.slice();for(let i=a.length-1;i>0;i--){const j=Math.random()*(i+1)|0;[a[i],a[j]]=[a[j],a[i]]}return a}
|
||||
|
||||
function deckFor(m){
|
||||
if(m==="review") return reviewDeck();
|
||||
if(m==="weak") return weakDeck();
|
||||
if(m==="vocab") return shuffle(vocabItems());
|
||||
if(m==="verbstem") return shuffle(verbItems());
|
||||
if(m==="sentence") return shuffle(sentenceItems());
|
||||
if(m==="phrases") return shuffle(phraseItems());
|
||||
if(m==="particle") return shuffle(particleItems());
|
||||
return [];
|
||||
}
|
||||
function start(m, all=false){
|
||||
mode=m; idx=0; correct=0; total=0; sessionAll=all;
|
||||
document.querySelectorAll("nav button").forEach(b=>b.classList.toggle("active",b.dataset.mode===m));
|
||||
queue=deckFor(m);
|
||||
// heute schon Erledigtes ausblenden – aber NICHT im "schwache Karten"-Modus (der soll die heute verpatzten nochmal bringen)
|
||||
if(!all && m!=='weak') queue=queue.filter(it=>!(it.id && doneToday(it.id)));
|
||||
updateGrammarNote();
|
||||
render();
|
||||
}
|
||||
function updateGrammarNote(){
|
||||
const el=document.getElementById('grammarNote'); if(!el)return;
|
||||
const ls=lessonsActive();
|
||||
if(ls.length===1 && ls[0].grammar && ['review','vocab','verbstem','sentence','particle'].includes(mode)){
|
||||
el.style.display='block'; el.innerHTML='<b>'+ls[0].code+'</b> · '+ls[0].grammar;
|
||||
} else el.style.display='none';
|
||||
}
|
||||
|
||||
function updateBar(){
|
||||
const len=queue.length||1;
|
||||
bar.style.width=(Math.min(idx,len)/len*100)+"%";
|
||||
counter.textContent = (mode==='unterricht'||mode==='stats')?'' : `${Math.min(idx+1,queue.length)} / ${queue.length}`;
|
||||
scoreEl.textContent = total>0 ? `✓ ${correct}/${total}` : "";
|
||||
}
|
||||
|
||||
function next(ok){
|
||||
total++; if(ok)correct++;
|
||||
const it=queue[idx];
|
||||
if(it && it.id) bump(it.id, ok);
|
||||
if(!ok && it) queue.push(it);
|
||||
idx++; render();
|
||||
}
|
||||
|
||||
function render(){
|
||||
updateBar();
|
||||
if(mode==='stats'){ renderStats(); return; }
|
||||
if(mode==='unterricht'){ renderUnterricht(); return; }
|
||||
if((GENERIC.includes(mode)||mode==='particle') && queue.length===0){
|
||||
let msg;
|
||||
if(mode==='weak')
|
||||
msg=`<div style="font-size:40px">💪</div><h2>Keine schwachen Karten!</h2>
|
||||
<p>Alles sitzt gerade gut. Mach eine Runde <b>🔁 Wiederholen</b>, dann füllt sich hier wieder was.</p>
|
||||
<button class="btn btn-primary" onclick="start('review')">Zum Wiederholen</button>`;
|
||||
else if(deckFor(mode).length===0)
|
||||
msg=`<div style="font-size:40px">📭</div><h2>Keine Aufgaben hier</h2>
|
||||
<p>Diese Lektion hat für diesen Modus keine Karten. Wähle oben eine andere Lektion oder einen anderen Reiter.</p>`;
|
||||
else if(!sessionAll)
|
||||
msg=`<div style="font-size:40px">✅</div><h2>Für heute erledigt!</h2>
|
||||
<p>Diese Übung hast du heute schon komplett durch. Morgen kommen die Karten automatisch wieder.</p>
|
||||
<button class="btn btn-primary" onclick="start('${mode}',true)">Trotzdem nochmal (alle)</button>`;
|
||||
else
|
||||
msg=`<div style="font-size:40px">🎉</div><h2>Nichts mehr zu üben.</h2>`;
|
||||
app.innerHTML=`<div class="card empty">${msg}</div>`; bar.style.width='100%'; return;
|
||||
}
|
||||
if(idx>=queue.length){ done(); return; }
|
||||
if(mode==='particle'){ renderParticle(); return; }
|
||||
renderCard();
|
||||
}
|
||||
|
||||
function done(){
|
||||
const pct=total?Math.round(correct/total*100):0;
|
||||
app.innerHTML=`<div class="card done">
|
||||
<div class="big">${pct>=80?"🎉":pct>=50?"👍":"💪"}</div>
|
||||
<h2>Fertig!</h2><p>${correct} von ${total} richtig · ${pct}%</p>
|
||||
<button class="btn btn-primary" onclick="start('${mode}',true)">Nochmal</button></div>`;
|
||||
bar.style.width="100%";
|
||||
}
|
||||
|
||||
/* ========== GENERISCHE KARTE (Selbstkontrolle ODER Tippen) ========== */
|
||||
function methodToggle(hasType){
|
||||
const dirSel = (mode==='vocab')
|
||||
? `<select class="sel" id="dir">
|
||||
<option value="deJp"${dir==='deJp'?' selected':''}>DE → JP</option>
|
||||
<option value="jpDe"${dir==='jpDe'?' selected':''}>JP → DE</option></select>` : '';
|
||||
const mSel = hasType
|
||||
? `<select class="sel" id="method">
|
||||
<option value="self"${method==='self'?' selected':''}>Selbstkontrolle</option>
|
||||
<option value="type"${method==='type'?' selected':''}>Tippen</option></select>` : '';
|
||||
return `<div class="barctl"><span class="prompt-label">${modeLabel()}</span><span>${dirSel} ${mSel}</span></div>`;
|
||||
}
|
||||
function modeLabel(){
|
||||
return {review:'Wiederholen',vocab:dir==='deJp'?'Deutsch → 日本語':'日本語 → Deutsch',
|
||||
verbstem:'Verbstamm bilden',sentence:'Satz bauen',phrases:'Unterrichts-Satz'}[mode]||'';
|
||||
}
|
||||
|
||||
function renderCard(){
|
||||
const it=queue[idx];
|
||||
const hasType = !!it.typeTarget;
|
||||
const useType = hasType && method==='type';
|
||||
app.innerHTML=`<div class="card">
|
||||
${methodToggle(hasType)}
|
||||
${it.front}
|
||||
<div id="ans" class="hidden">${it.back}${it.id?('<div class="reading" style="margin-top:8px">Level: '+boxesHtml(it.id)+'</div>'):''}</div>
|
||||
<div id="io"></div>
|
||||
<div class="tip">${useType?'Tippe Kana <b>oder</b> Rōmaji (z.B. „tabe" → たべ). Enter prüft.':'Sag die Antwort <b>laut</b>, bevor du aufdeckst.'}</div>
|
||||
</div>`;
|
||||
const d=document.getElementById('dir'); if(d) d.onchange=e=>{dir=e.target.value;localStorage.setItem('kody_dir',dir);start('vocab');};
|
||||
const mm=document.getElementById('method'); if(mm) mm.onchange=e=>{method=e.target.value;localStorage.setItem('kody_method',method);render();};
|
||||
|
||||
const io=document.getElementById('io');
|
||||
if(useType){
|
||||
io.innerHTML=`<input class="type" id="inp" autocomplete="off" autocapitalize="off" spellcheck="false" placeholder="…">
|
||||
<div id="fb" class="feedback"></div>
|
||||
<button class="btn btn-primary" id="chk" style="margin-top:14px">Prüfen</button>`;
|
||||
const inp=document.getElementById('inp'); inp.focus();
|
||||
const check=()=>{
|
||||
const ok = norm(inp.value)===norm(it.typeTarget);
|
||||
document.getElementById('ans').classList.remove('hidden');
|
||||
inp.classList.add(ok?'ok':'bad');
|
||||
document.getElementById('fb').innerHTML = ok
|
||||
? '<span style="color:var(--green)">✓ Richtig!</span>'
|
||||
: `<span style="color:var(--wo)">Du: ${toKana(inp.value)||'—'} · Richtig: ${it.typeTarget}</span>`;
|
||||
document.getElementById('io').querySelector('#chk').outerHTML =
|
||||
ok ? `<button class="btn btn-primary" style="margin-top:14px" onclick="next(true)">Weiter →</button>`
|
||||
: `<div class="btn-row"><button class="btn btn-no" onclick="next(false)">Weiter (falsch)</button>
|
||||
<button class="btn btn-ok" onclick="next(true)">War doch richtig ✓</button></div>`;
|
||||
};
|
||||
document.getElementById('chk').onclick=check;
|
||||
inp.addEventListener('keydown',e=>{if(e.key==='Enter')check();});
|
||||
} else {
|
||||
io.innerHTML=`<button class="btn btn-primary" style="margin-top:16px" onclick="reveal()">Antwort zeigen</button>`;
|
||||
window.reveal=()=>{
|
||||
document.getElementById('ans').classList.remove('hidden');
|
||||
io.innerHTML=`<div class="btn-row">
|
||||
<button class="btn btn-no" onclick="next(false)">✗ Nochmal</button>
|
||||
<button class="btn btn-ok" onclick="next(true)">✓ Gewusst</button></div>`;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/* ========== PARTIKEL ========== */
|
||||
let pFill=[], activeSlot=0;
|
||||
function renderParticle(){
|
||||
const q=queue[idx]; pFill=q.ans.map(()=>null); let slot=-1;
|
||||
const html=q.parts.map(p=>{ if(p==="___"){slot++;const s=slot;return `<span class="slot" id="slot${s}" onclick="selSlot(${s})">_</span>`;} return p;}).join(" ");
|
||||
app.innerHTML=`<div class="card">
|
||||
<span class="prompt-label">Setz die Partikel ein</span>
|
||||
<div class="en" style="margin-bottom:6px">${q.hint}</div>
|
||||
<div class="blanks">${html}</div>
|
||||
<div class="choices">${CHOICES.map(c=>`<button onclick="pick('${c}')">${c}</button>`).join("")}</div>
|
||||
<div id="fb" class="feedback"></div>
|
||||
<div id="ctl"><button class="btn btn-primary" style="margin-top:16px" onclick="checkP()">Prüfen</button></div>
|
||||
<div class="tip"><span class="p-ni">に</span> Ziel/Zweck · <span class="p-wo">を</span> Objekt · <span class="p-de">で</span> Ort der Handlung</div>
|
||||
</div>`;
|
||||
activeSlot=0; hi();
|
||||
}
|
||||
function hi(){document.querySelectorAll(".slot").forEach((s,i)=>s.style.background=i===activeSlot?"#fef6e8":"");}
|
||||
window.selSlot=i=>{activeSlot=i;hi();};
|
||||
window.pick=c=>{ pFill[activeSlot]=c; const el=document.getElementById("slot"+activeSlot); el.textContent=c; el.classList.add("filled"); if(activeSlot<pFill.length-1){activeSlot++;hi();}};
|
||||
window.checkP=()=>{
|
||||
const q=queue[idx]; const fb=document.getElementById("fb");
|
||||
if(pFill.includes(null)){fb.innerHTML='<span style="color:var(--wo)">Erst alle Lücken füllen.</span>';return;}
|
||||
const ok=pFill.every((p,i)=>p===q.ans[i]);
|
||||
if(ok){ fb.innerHTML='<span style="color:var(--green)">✓ Perfekt!</span>'; document.querySelectorAll(".slot").forEach(s=>s.style.color="var(--green)");
|
||||
document.getElementById("ctl").innerHTML=`<button class="btn btn-primary" style="margin-top:16px" onclick="next(true)">Weiter →</button>`;
|
||||
}else{ fb.innerHTML='<span style="color:var(--wo)">Richtig: '+q.ans.join(" · ")+'</span>';
|
||||
document.getElementById("ctl").innerHTML=`<button class="btn btn-primary" style="margin-top:16px" onclick="next(false)">Weiter →</button>`; }
|
||||
};
|
||||
|
||||
/* ========== FORTSCHRITT / STATISTIK ========== */
|
||||
function renderStats(){
|
||||
bar.style.width="100%"; counter.textContent=''; scoreEl.textContent='';
|
||||
const meta=allMeta();
|
||||
let att=0, mastered=0, right=0, wrong=0, last=0, newCount=0;
|
||||
meta.forEach(m=>{const r=STATS[m.id];
|
||||
if(r&&(r.right+r.wrong>0)){att++; right+=r.right; wrong+=r.wrong; if(r.box>=4)mastered++; if(r.last>last)last=r.last;}
|
||||
else newCount++;});
|
||||
const acc = (right+wrong)? Math.round(right/(right+wrong)*100) : 0;
|
||||
const weak=weakList().slice(0,12);
|
||||
const strong=meta.filter(m=>{const r=STATS[m.id]; return r&&r.box>=4;}).slice(0,12);
|
||||
const lastTxt = last? new Date(last).toLocaleDateString('de-DE',{day:'2-digit',month:'2-digit',year:'2-digit',hour:'2-digit',minute:'2-digit'}) : '—';
|
||||
|
||||
const rowHtml=(m)=>{const r=STATS[m.id]||{right:0,wrong:0};
|
||||
return `<div class="row"><span class="lbl">${m.label}</span>
|
||||
<span class="rt">${boxesHtml(m.id)} <span class="ok">✓${r.right}</span> <span class="bad">✗${r.wrong}</span></span></div>`;};
|
||||
|
||||
app.innerHTML=`
|
||||
<div class="tiles">
|
||||
<div class="tile"><b>${att}</b><span>geübt</span></div>
|
||||
<div class="tile"><b>${mastered}</b><span>gemeistert</span></div>
|
||||
<div class="tile"><b>${acc}%</b><span>Genauigkeit</span></div>
|
||||
</div>
|
||||
<div class="note">Von ${meta.length} Karten sind ${newCount} noch neu. Zuletzt geübt: ${lastTxt}.</div>
|
||||
|
||||
<h2 class="section">⚠️ Schwach — üben!</h2>
|
||||
${weak.length? `<button class="btn btn-primary" style="margin-bottom:10px" onclick="start('weak')">🎯 Nur diese ${weakList().length} schwachen Karten üben</button>
|
||||
${weak.map(rowHtml).join("")}` : `<div class="empty">Noch keine Schwachstellen — oder noch nichts geübt. 🙂</div>`}
|
||||
|
||||
<h2 class="section">💪 Stark</h2>
|
||||
${strong.length? strong.map(rowHtml).join("") : `<div class="empty">Noch keine gemeisterten Karten. Üben lohnt sich!</div>`}
|
||||
|
||||
<button class="btn btn-reset" onclick="resetStats()">🗑️ Fortschritt zurücksetzen</button>`;
|
||||
}
|
||||
window.resetStats=()=>{ if(confirm('Wirklich den gesamten Lernfortschritt löschen?')){ STATS={}; saveStats(); localStorage.removeItem('kody_leitner'); renderStats(); } };
|
||||
|
||||
/* ========== UNTERRICHT (Verhalten + Sätze) ========== */
|
||||
function renderUnterricht(){
|
||||
bar.style.width="100%";
|
||||
app.innerHTML=`<div class="card">
|
||||
<span class="prompt-label">Verhalten im Unterricht</span>
|
||||
<ul class="beh">
|
||||
<li><b>Aktiv sprechen.</b> Antworte in ganzen Sätzen — dein Ziel ist Produktion, nicht nur Verstehen.</li>
|
||||
<li><b>Nicht schweigen.</b> Wenn du hängst, sag es auf Japanisch: „ちょっと待ってください" statt Pause.</li>
|
||||
<li><b>Nachfragen auf Japanisch.</b> Nutze die Sätze unten, statt ins Deutsche/Englische zu wechseln.</li>
|
||||
<li><b>Laut & deutlich.</b> Lieber falsch und laut als richtig und leise.</li>
|
||||
<li><b>Mitschreiben.</b> Neue Wörter sofort in die App / Notizen.</li>
|
||||
<li><b>Begrüßung:</b> zu Beginn „よろしくお願いします", am Ende „ありがとうございました".</li>
|
||||
</ul>
|
||||
<button class="btn btn-primary" style="margin-top:18px" onclick="start('phrases')">🎯 Diese Sätze üben (DE → JP)</button>
|
||||
</div>
|
||||
<h2 class="section">Nützliche Sätze im Unterricht</h2>
|
||||
${PHRASES.map(p=>`<div class="phrase"><div class="jp">${p.jpr}</div><div class="reading">${p.read}</div><div class="de">${p.de}</div></div>`).join("")}`;
|
||||
counter.textContent=''; scoreEl.textContent='';
|
||||
}
|
||||
|
||||
/* ========== INIT ========== */
|
||||
function fillLessonSel(){
|
||||
const sel=document.getElementById('lessonSel');
|
||||
let html=LESSONS.map(l=>`<option value="${l.id}">${l.code} · ${l.title}</option>`).join('');
|
||||
if(LESSONS.length>1) html+=`<option value="all">🔀 Alle Lektionen (gemischt)</option>`;
|
||||
sel.innerHTML=html; sel.value=lesson;
|
||||
sel.onchange=e=>{ lesson=e.target.value; localStorage.setItem('kody_lesson',lesson); start(mode); };
|
||||
}
|
||||
fillLessonSel();
|
||||
document.querySelectorAll("nav button").forEach(b=>b.onclick=()=>start(b.dataset.mode));
|
||||
start("review");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
47
apps/nihongo/deployment.yaml
Normal file
47
apps/nihongo/deployment.yaml
Normal file
@@ -0,0 +1,47 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nihongo
|
||||
namespace: nihongo
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nihongo
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nihongo
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.27-alpine
|
||||
ports:
|
||||
- containerPort: 80
|
||||
volumeMounts:
|
||||
- name: html
|
||||
mountPath: /usr/share/nginx/html
|
||||
readOnly: true
|
||||
resources:
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 16Mi
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 64Mi
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: 80
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: 80
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 30
|
||||
volumes:
|
||||
- name: html
|
||||
configMap:
|
||||
name: nihongo-html
|
||||
25
apps/nihongo/ingress.yaml
Normal file
25
apps/nihongo/ingress.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: nihongo-ingress
|
||||
namespace: nihongo
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: web, websecure
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
rules:
|
||||
- host: nihongo.unreg-hdw.de
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: nihongo-service
|
||||
port:
|
||||
number: 80
|
||||
tls:
|
||||
- hosts:
|
||||
- nihongo.unreg-hdw.de
|
||||
secretName: nihongo-tls-cert
|
||||
4
apps/nihongo/namespace.yaml
Normal file
4
apps/nihongo/namespace.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: nihongo
|
||||
12
apps/nihongo/service.yaml
Normal file
12
apps/nihongo/service.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nihongo-service
|
||||
namespace: nihongo
|
||||
spec:
|
||||
selector:
|
||||
app: nihongo
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
targetPort: 80
|
||||
Reference in New Issue
Block a user