Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions app/learn/chinese/01/characters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// 基本的な漢字1字と、その普通話(標準中国語)でのピンイン。
// pinyin は声調記号付きの表記(軽声は記号なし)。多音字は避け、代表的な読みが1つに定まる字だけを収録している。

export interface HanziEntry {
id: string;
hanzi: string;
// 声調記号付きピンイン(例: "wǒ"、軽声は "ma")
pinyin: string;
// 日本語での意味・用法
meaning: string;
}

export const characters: HanziEntry[] = [
// 数字
{ id: "yi", hanzi: "一", pinyin: "yī", meaning: "1" },
{ id: "er", hanzi: "二", pinyin: "èr", meaning: "2" },
{ id: "san", hanzi: "三", pinyin: "sān", meaning: "3" },
{ id: "si", hanzi: "四", pinyin: "sì", meaning: "4" },
{ id: "wu", hanzi: "五", pinyin: "wǔ", meaning: "5" },
{ id: "liu", hanzi: "六", pinyin: "liù", meaning: "6" },
{ id: "qi", hanzi: "七", pinyin: "qī", meaning: "7" },
{ id: "ba", hanzi: "八", pinyin: "bā", meaning: "8" },
{ id: "jiu", hanzi: "九", pinyin: "jiǔ", meaning: "9" },
{ id: "shi10", hanzi: "十", pinyin: "shí", meaning: "10" },

// 代名詞・基本動詞・助詞
{ id: "wo", hanzi: "我", pinyin: "wǒ", meaning: "わたし" },
{ id: "ni", hanzi: "你", pinyin: "nǐ", meaning: "あなた" },
{ id: "ta-he", hanzi: "他", pinyin: "tā", meaning: "彼" },
{ id: "ta-she", hanzi: "她", pinyin: "tā", meaning: "彼女" },
{ id: "shi-be", hanzi: "是", pinyin: "shì", meaning: "〜である" },
{ id: "bu", hanzi: "不", pinyin: "bù", meaning: "〜でない(否定)" },
{ id: "you-have", hanzi: "有", pinyin: "yǒu", meaning: "ある・持つ" },
{ id: "zai", hanzi: "在", pinyin: "zài", meaning: "〜にある/〜で" },
{ id: "hao", hanzi: "好", pinyin: "hǎo", meaning: "よい" },
{ id: "hen", hanzi: "很", pinyin: "hěn", meaning: "とても" },
{ id: "ma-q", hanzi: "吗", pinyin: "ma", meaning: "〜か(疑問/軽声)" },
{ id: "de-poss", hanzi: "的", pinyin: "de", meaning: "〜の(軽声)" },

// 方向・大小・自然
{ id: "zhong", hanzi: "中", pinyin: "zhōng", meaning: "中・中国" },
{ id: "guo", hanzi: "国", pinyin: "guó", meaning: "国" },
{ id: "ren", hanzi: "人", pinyin: "rén", meaning: "人" },
{ id: "da", hanzi: "大", pinyin: "dà", meaning: "大きい" },
{ id: "xiao", hanzi: "小", pinyin: "xiǎo", meaning: "小さい" },
{ id: "duo", hanzi: "多", pinyin: "duō", meaning: "多い" },
{ id: "shang", hanzi: "上", pinyin: "shàng", meaning: "上" },
{ id: "xia", hanzi: "下", pinyin: "xià", meaning: "下" },
{ id: "tian", hanzi: "天", pinyin: "tiān", meaning: "空・日" },
{ id: "ri", hanzi: "日", pinyin: "rì", meaning: "日・太陽" },
{ id: "yue", hanzi: "月", pinyin: "yuè", meaning: "月" },
{ id: "nian", hanzi: "年", pinyin: "nián", meaning: "年" },
{ id: "shui", hanzi: "水", pinyin: "shuǐ", meaning: "水" },
{ id: "huo", hanzi: "火", pinyin: "huǒ", meaning: "火" },
{ id: "shan", hanzi: "山", pinyin: "shān", meaning: "山" },

// 人・暮らし
{ id: "nu", hanzi: "女", pinyin: "nǚ", meaning: "女" },
{ id: "nan", hanzi: "男", pinyin: "nán", meaning: "男" },
{ id: "ming", hanzi: "名", pinyin: "míng", meaning: "名前" },
{ id: "zi-char", hanzi: "字", pinyin: "zì", meaning: "字" },
{ id: "shu-book", hanzi: "书", pinyin: "shū", meaning: "本" },
{ id: "jia", hanzi: "家", pinyin: "jiā", meaning: "家" },
{ id: "ai", hanzi: "爱", pinyin: "ài", meaning: "愛する" },
{ id: "xue", hanzi: "学", pinyin: "xué", meaning: "学ぶ" },
{ id: "ma-horse", hanzi: "马", pinyin: "mǎ", meaning: "馬" },
{ id: "niao", hanzi: "鸟", pinyin: "niǎo", meaning: "鳥" },

// 動作
{ id: "chi", hanzi: "吃", pinyin: "chī", meaning: "食べる" },
{ id: "he-drink", hanzi: "喝", pinyin: "hē", meaning: "飲む" },
{ id: "kan", hanzi: "看", pinyin: "kàn", meaning: "見る" },
{ id: "qu", hanzi: "去", pinyin: "qù", meaning: "行く" },
{ id: "lai", hanzi: "来", pinyin: "lái", meaning: "来る" },
];
12 changes: 0 additions & 12 deletions app/learn/chinese/01/page.mdx

This file was deleted.

21 changes: 21 additions & 0 deletions app/learn/chinese/01/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"use client";

import { PinyinPractice } from "@/components/pinyin/PinyinPractice";
import { characters } from "./characters";

export const title = "漢字からピンイン";

export default function ChinesePinyinPage() {
return (
<div>
<h1 className="text-2xl font-bold text-zinc-800 dark:text-zinc-100">漢字からピンイン</h1>
<p className="mt-2 text-zinc-600 dark:text-zinc-400">
基本的な漢字を1字ずつ見て、ピンインを入力しましょう。四声は母音を入力した直後に
↑/↓キーで選べます。
</p>
<div className="mt-8">
<PinyinPractice characters={characters} />
</div>
</div>
);
}
16 changes: 14 additions & 2 deletions app/learn/content.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { existsSync } from "node:fs";
import { readdir } from "node:fs/promises";
import path from "node:path";

Expand Down Expand Up @@ -44,6 +45,13 @@ async function listSlugs(languageSlug: string): Promise<string[]> {
);
}

// 任意のセクションについて、page.mdx / page.tsx のうち実際に存在する方の拡張子を返す関数
// (動詞活用ドリルのような練習教材は、静的なMDXではなくインタラクティブなpage.tsxとして実装されるため)
function resolveSectionExtension(languageSlug: string, sectionSlug: string): "mdx" | "tsx" {
const dirPath = path.join(process.cwd(), "app", "learn", languageSlug, sectionSlug);
return existsSync(path.join(dirPath, "page.tsx")) ? "tsx" : "mdx";
}

// 任意の言語について、セクションの番号配列を返す関数
export async function getSections(languageSlug: string): Promise<SectionSummary[]> {
const sectionSlugs = await listSlugs(languageSlug);
Expand All @@ -52,8 +60,12 @@ export async function getSections(languageSlug: string): Promise<SectionSummary[
return Promise.all(
sectionSlugs.map(async (sectionSlug) => {
// ここでのimport()は動的インポートであり、指定されたパスの情報を読み込む
// page.mdxファイルの中からtitleプロパティを、分割代入によって取得している
const { title } = await import(`./${languageSlug}/${sectionSlug}/page.mdx`);
// page.mdx / page.tsx ファイルの中からtitleプロパティを、分割代入によって取得している
const extension = resolveSectionExtension(languageSlug, sectionSlug);
const { title } =
extension === "tsx"
? await import(`./${languageSlug}/${sectionSlug}/page.tsx`)
: await import(`./${languageSlug}/${sectionSlug}/page.mdx`);
return { sectionSlug, title };
}),
);
Expand Down
30 changes: 0 additions & 30 deletions app/learn/french/01/page.mdx

This file was deleted.

19 changes: 19 additions & 0 deletions app/learn/french/01/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"use client";

import { ConjugationPractice } from "@/components/verbs/ConjugationPractice";
import { frenchConjugationConfig } from "@/lib/conjugation/fr/config";
import { verbs } from "./verbs";

export const title = "動詞の活用";

export default function FrenchVerbConjugationPage() {
return (
<div>
<h1>動詞の活用</h1>
<p>動詞・時制・法を選んで、活用形を入力しながら覚えましょう。</p>
<div className="mt-8">
<ConjugationPractice verbs={verbs} language={frenchConjugationConfig} />
</div>
</div>
);
}
Loading