diff --git a/app/learn/chinese/02/page.tsx b/app/learn/chinese/02/page.tsx index b640852..64dccd0 100644 --- a/app/learn/chinese/02/page.tsx +++ b/app/learn/chinese/02/page.tsx @@ -1,20 +1,18 @@ "use client"; -import { PinyinPractice } from "@/components/pinyin/PinyinPractice"; -import { characters } from "./characters"; +import { TranslationPractice } from "@/components/translation/TranslationPractice"; -export const title = "漢字からピンイン"; +export const title = "翻訳"; -export default function ChinesePinyinPage() { +export default function ChineseTranslationPage() { return (
-

漢字からピンイン

+

翻訳

- 基本的な漢字を1字ずつ見て、ピンインを入力しましょう。四声は母音を入力した直後に - ↑/↓キーで選べます。 + 中国語⇔日本語の訳文を書き、AIに添削してもらいましょう。

- +
); diff --git a/app/learn/chinese/02/characters.ts b/app/learn/chinese/03/characters.ts similarity index 100% rename from app/learn/chinese/02/characters.ts rename to app/learn/chinese/03/characters.ts diff --git a/app/learn/chinese/03/page.tsx b/app/learn/chinese/03/page.tsx new file mode 100644 index 0000000..b640852 --- /dev/null +++ b/app/learn/chinese/03/page.tsx @@ -0,0 +1,21 @@ +"use client"; + +import { PinyinPractice } from "@/components/pinyin/PinyinPractice"; +import { characters } from "./characters"; + +export const title = "漢字からピンイン"; + +export default function ChinesePinyinPage() { + return ( +
+

漢字からピンイン

+

+ 基本的な漢字を1字ずつ見て、ピンインを入力しましょう。四声は母音を入力した直後に + ↑/↓キーで選べます。 +

+
+ +
+
+ ); +} diff --git a/app/learn/french/02/page.tsx b/app/learn/french/02/page.tsx index 71d6e16..68e9c8f 100644 --- a/app/learn/french/02/page.tsx +++ b/app/learn/french/02/page.tsx @@ -1,18 +1,16 @@ "use client"; -import { ConjugationPractice } from "@/components/verbs/ConjugationPractice"; -import { frenchConjugationConfig } from "@/lib/conjugation/fr/config"; -import { verbs } from "./verbs"; +import { TranslationPractice } from "@/components/translation/TranslationPractice"; -export const title = "動詞の活用"; +export const title = "翻訳"; -export default function FrenchVerbConjugationPage() { +export default function FrenchTranslationPage() { return (
-

動詞の活用

-

動詞・時制・法を選んで、活用形を入力しながら覚えましょう。

+

翻訳

+

フランス語⇔日本語の訳文を書き、AIに添削してもらいましょう。

- +
); diff --git a/app/learn/french/03/page.mdx b/app/learn/french/03/page.mdx deleted file mode 100644 index 8c8b82e..0000000 --- a/app/learn/french/03/page.mdx +++ /dev/null @@ -1,30 +0,0 @@ -export const title = "冠詞の一覧と縮約形"; - -# 冠詞の一覧と縮約形 - -_第1章 品詞と文型より_ - -## 冠詞の種類 - -| | | | 男性形 | 女性形 | -| ------ | -------- | ------ | ---------- | ------------- | -| 可算 | 不定冠詞 | 単数形 | un | une | -| 可算 | 不定冠詞 | 複数形 | des | des | -| 可算 | 定冠詞 | 単数形 | le (l') | la (l') | -| 可算 | 定冠詞 | 複数形 | les | les | -| 不可算 | 部分冠詞 | - | du (de l') | de la (de l') | -| 不可算 | 定冠詞 | - | le (l') | la (l') | - -- 括弧内は直後の名詞が母音始まりの時に用いる。 -- 「du」は「de le」の短縮版であり、部分冠詞は「de+定冠詞」で作られると考えてよい。 - -## 冠詞の縮約形 - -- à+le → au、à+les → aux -- de+le → du、de+les → des - -## 否定文における冠詞「de」 - -否定文において、①不定冠詞や部分冠詞が、②直接目的語に付いている場合、冠詞が「de」に変化する。 - -- J'ai un chien. → Je n'ai pas de chien. diff --git a/app/learn/french/03/page.tsx b/app/learn/french/03/page.tsx new file mode 100644 index 0000000..98578d6 --- /dev/null +++ b/app/learn/french/03/page.tsx @@ -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 ( +
+

動詞の活用

+

動詞・時制・法を選んで、活用形を入力しながら覚えましょう。

+
+ +
+
+ ); +} diff --git a/app/learn/french/02/verbs.ts b/app/learn/french/03/verbs.ts similarity index 100% rename from app/learn/french/02/verbs.ts rename to app/learn/french/03/verbs.ts diff --git a/app/learn/french/04/page.mdx b/app/learn/french/04/page.mdx deleted file mode 100644 index a3dfbb8..0000000 --- a/app/learn/french/04/page.mdx +++ /dev/null @@ -1,66 +0,0 @@ -export const title = "基本動詞の直説法現在活用"; - -# 基本動詞の直説法現在活用 - -_第1章 品詞と文型より_ - -## être(be動詞) - -| 人称 | 活用形 | 人称 | 活用形 | -| ---------- | ------ | ---------- | ------ | -| 一人称単数 | suis | 一人称複数 | sommes | -| 二人称単数 | es | 二人称複数 | êtes | -| 三人称単数 | est | 三人称複数 | sont | - -## avoir(have) - -| 人称 | 活用形 | 人称 | 活用形 | -| ---------- | ------ | ---------- | ------ | -| 一人称単数 | ai | 一人称複数 | avons | -| 二人称単数 | as | 二人称複数 | avez | -| 三人称単数 | a | 三人称複数 | ont | - -## faire(make, do) - -| 人称 | 活用形 | 人称 | 活用形 | -| ---------- | ------ | ---------- | ------- | -| 一人称単数 | fais | 一人称複数 | faisons | -| 二人称単数 | fais | 二人称複数 | faites | -| 三人称単数 | fait | 三人称複数 | font | - -## aller(go) - -| 人称 | 活用形 | 人称 | 活用形 | -| ---------- | ------ | ---------- | ------ | -| 一人称単数 | vais | 一人称複数 | allons | -| 二人称単数 | vas | 二人称複数 | allez | -| 三人称単数 | va | 三人称複数 | vont | - -## venir(come) - -| 人称 | 活用形 | 人称 | 活用形 | -| ---------- | ------ | ---------- | -------- | -| 一人称単数 | viens | 一人称複数 | venons | -| 二人称単数 | viens | 二人称複数 | venez | -| 三人称単数 | vient | 三人称複数 | viennent | - -## -er動詞 - -| 人称 | 語尾 | 人称 | 語尾 | -| ---------- | ---- | ---------- | ---- | -| 一人称単数 | -e | 一人称複数 | -ons | -| 二人称単数 | -es | 二人称複数 | -ez | -| 三人称単数 | -e | 三人称複数 | -ent | - -- -gerで終わる動詞(manger等)の一人称複数形は -geons -- -cerで終わる動詞(commencer等)の一人称複数形は -çons - -## -ir動詞 - -| 人称 | 語尾 | 人称 | 語尾 | -| ---------- | ---- | ---------- | ------- | -| 一人称単数 | -is | 一人称複数 | -issons | -| 二人称単数 | -is | 二人称複数 | -issez | -| 三人称単数 | -it | 三人称複数 | -issent | - -- 複数形の活用は「-iss+er動詞の活用形」の形になっている。 diff --git a/app/learn/french/05/page.mdx b/app/learn/french/05/page.mdx deleted file mode 100644 index 3eef46d..0000000 --- a/app/learn/french/05/page.mdx +++ /dev/null @@ -1,64 +0,0 @@ -export const title = "基数と序数と概数"; - -# 基数と序数と概数 - -_第1章 品詞と文型より_ - -## 基数(0〜19) - -| 数 | 綴り | 数 | 綴り | -| --- | --------- | --- | -------- | -| 0 | zéro | 10 | dix | -| 1 | un(une) | 11 | onze | -| 2 | deux | 12 | douze | -| 3 | trois | 13 | treize | -| 4 | quatre | 14 | quatorze | -| 5 | cinq | 15 | quinze | -| 6 | six | 16 | seize | -| 7 | sept | 17 | dix-sept | -| 8 | huit | 18 | dix-huit | -| 9 | neuf | 19 | dix-neuf | - -## 基数(20の倍数) - -| 数 | 綴り | 数 | 綴り | -| --- | ------------- | --- | --------- | -| 20 | vingt | 30 | trente | -| 40 | quarante | 50 | cinquante | -| 60 | soixante | - | - | -| 80 | quatre-vingts | - | - | - -- 21〜99は上記の組み合わせで表現する:「{"A"の数字と"B"の数字の和となる基数}={"B"の基数}-{"A"の基数}」 - - 22:vingt-deux(20+2) - - 75:soixante-quinze(60+15) -- "B"として80を組み合わせに用いる場合は「quatre-vingt」(sなし)になる。 -- 基数10〜19を組み合わせで使うのは70〜79及び90〜99を表すときのみ。 -- 一桁目が1を含むとき、間に「et」を挟んでハイフンでつなぐ。 - - 31:trente-et-un - - 91:quatre-vingt-onze - -## 3桁以上の基数 - -| 桁 | 数 | 綴り | -| ------- | ----------------- | -------- | -| 3桁 | 100 | cent | -| 4桁以上 | 1.000 | mille | -| 4桁以上 | 1.000.000 | million | -| 4桁以上 | 1.000.000.000 | milliard | -| 4桁以上 | 1.000.000.000.000 | billion | - -## 序数 - -原則:基数の後ろに-ièmeをつける。 - -- deux → deuxième -- eで終わる数字はeを取ってièmeをつける(quatre → quatrième) -- 「un(une)」は不規則で「premier(première)」 -- cinq は語尾にuを加えて「cinquième」 -- neuf は語尾のfがvになり「neuvième」 - -## 概数 - -基数の語尾に-aineを付けて作る。女性名詞として扱われるため、不定冠詞「une」や定冠詞「la」を伴うことがほとんど(1000の概数millierだけ男性名詞)。後ろに名詞が続く場合は前置詞「de」が必要。 - -- vingt → vingtaine diff --git a/app/learn/french/06/page.mdx b/app/learn/french/06/page.mdx deleted file mode 100644 index 311db40..0000000 --- a/app/learn/french/06/page.mdx +++ /dev/null @@ -1,24 +0,0 @@ -export const title = "時刻表現"; - -# 時刻表現 - -_第1章 品詞と文型より_ - -「〜時(〜分)」は「〜heures(〜)」で表現する。 - -- Il est deux heures dix. (2時10分です。) - -## 定型表現 - -- 「〜時15分」は「et quart」 -- 「〜時30分」は「et demi(e)」 -- 「〜時15分前」は「moins le quart」 -- これらは「〜heures」の後に伴って表現する。 - - Il est sept heures et demie. (7時半です。) - -## 秒までの表記 - -時間帯を秒数まで細かく指定する場合、「et」を用いて秒数を続け、単位も記載する。表記は「heure → h、minute → min、seconde → s」とする。 - -- Il est seize heures vingt et une minute et dix-sept secondes. - = Il est 16 h 21 min 17 s.(16時21分17秒です。) diff --git a/app/learn/french/07/page.mdx b/app/learn/french/07/page.mdx deleted file mode 100644 index e2df8af..0000000 --- a/app/learn/french/07/page.mdx +++ /dev/null @@ -1,11 +0,0 @@ -export const title = "日程表現"; - -# 日程表現 - -_第1章 品詞と文型より_ - -事細かに表す場合は「le+曜日+日+月+年」で表現する。日程を単に述べる場合、その主語は「nous」または「on」になり、動詞には「être」を用いる。 - -- Nous sommes le lundi 3 janvier 2022. (2022年1月3日月曜日です。) - -「〜日」は通常基数で表すが、「1日」だけ例外で序数「premier」を使う。 diff --git a/app/learn/french/08/page.mdx b/app/learn/french/08/page.mdx deleted file mode 100644 index 13452e0..0000000 --- a/app/learn/french/08/page.mdx +++ /dev/null @@ -1,25 +0,0 @@ -export const title = "人称代名詞"; - -# 人称代名詞 - -_第3章 人称詞と指示詞より_ - -| | | 主語 | 直接目的語 | 間接目的語 | 強勢形 | -| ---------- | --- | ----- | ---------- | ---------- | ------ | -| 一人称単数 | | je | me | me | moi | -| 二人称単数 | | tu | te | te | toi | -| 三人称単数 | 男 | il | le | lui | lui | -| 三人称単数 | 女 | elle | la | lui | elle | -| 一人称複数 | | nous | nous | nous | nous | -| 二人称複数 | | vous | vous | vous | vous | -| 三人称複数 | 男 | ils | les | leur | eux | -| 三人称複数 | 女 | elles | les | leur | elles | - -- 強勢形は、前置詞の目的語や対比・強調などに用いられる。 -- 三人称の人称代名詞は非人称的な使い方で用いられることがある。 -- 目的語人称代名詞が再帰代名詞となる場合、三人称のものは「se」となる。 -- 不定主語の「on」(文法上は三人称単数)は「人は」「世間では」「一般に」「私たち」といった意味を持つ。 - - Il lit et l'on écoute. (彼が読み、人々が聞く。) - - この「l'」は母音で終わる特定の単語の後で母音の衝突を避けるために使われ、文法的な意味はない。 -- 目的語代名詞は原則動詞の前に持ってくる(不定詞などの場合でも同様)。 -- 複数の目的語代名詞が並ぶときの順序:「一・二人称間接目的語 → 三人称直接目的語 → 三人称間接目的語」。一・二人称直接目的語は他の目的語と同時には使えない。 diff --git a/app/learn/french/09/page.mdx b/app/learn/french/09/page.mdx deleted file mode 100644 index c29b720..0000000 --- a/app/learn/french/09/page.mdx +++ /dev/null @@ -1,17 +0,0 @@ -export const title = "所有形容詞"; - -# 所有形容詞 - -_第3章 人称詞と指示詞より_ - -| | 単数(男) | 単数(女) | 複数 | -| ---------- | ---------- | ---------- | ----- | -| 一人称単数 | mon | ma (mon) | mes | -| 二人称単数 | ton | ta (ton) | tes | -| 三人称単数 | son | sa (son) | ses | -| 一人称複数 | notre | notre | nos | -| 二人称複数 | votre | votre | vos | -| 三人称複数 | leur | leur | leurs | - -- 所有形容詞は、修飾する名詞によって形が変化する。 -- 修飾する語の先頭が母音時や無音のhの時、一部の女性形は括弧内のように変化する。 diff --git a/app/learn/french/10/page.mdx b/app/learn/french/10/page.mdx deleted file mode 100644 index 38022bd..0000000 --- a/app/learn/french/10/page.mdx +++ /dev/null @@ -1,16 +0,0 @@ -export const title = "所有代名詞"; - -# 所有代名詞 - -_第3章 人称詞と指示詞より_ - -英語のmineなどにあたり、「〜のもの」と訳される。常に定冠詞とセットで、置き換える「もの」の性数によって形が変化する。 - -| | 男性単数 | 女性単数 | 男性複数 | 女性複数 | -| ---------- | -------- | --------- | ---------- | ----------- | -| 一人称単数 | le mien | la mienne | les miens | les miennes | -| 二人称単数 | le tien | la tienne | les tiens | les tiennes | -| 三人称単数 | le sien | la sienne | les siens | les siennes | -| 一人称複数 | le nôtre | la nôtre | les nôtres | les nôtres | -| 二人称複数 | le vôtre | la vôtre | les vôtres | les vôtres | -| 三人称複数 | le leur | la leur | les leurs | les leurs | diff --git a/app/learn/french/11/page.mdx b/app/learn/french/11/page.mdx deleted file mode 100644 index 8945c51..0000000 --- a/app/learn/french/11/page.mdx +++ /dev/null @@ -1,15 +0,0 @@ -export const title = "指示形容詞"; - -# 指示形容詞 - -_第3章 人称詞と指示詞より_ - -「この」「その」「あの」に相当し、フランス語ではこれらすべてが同じ単語で表される。 - -| | 男性 | 女性 | -| ---- | -------- | ----- | -| 単数 | ce (cet) | cette | -| 複数 | ces | ces | - -- 修飾する名詞が母音始まりの男性単数形の時、発音の都合上cetを用いる。 -- 近称と遠称を区別したいときは、修飾する名詞の後ろに-ci(近称)や-là(遠称)をつける。 diff --git a/app/learn/french/12/page.mdx b/app/learn/french/12/page.mdx deleted file mode 100644 index b8e1d98..0000000 --- a/app/learn/french/12/page.mdx +++ /dev/null @@ -1,21 +0,0 @@ -export const title = "指示代名詞"; - -# 指示代名詞 - -_第3章 人称詞と指示詞より_ - -## パターン1 - -| | これ | それ | -| -------- | ---- | -------- | -| 無強勢形 | ce | ce | -| 強勢形 | ceci | cela(ça) | - -## パターン2 - -| | 男性 | 女性 | -| ---- | ----- | ------ | -| 単数 | celui | celle | -| 複数 | ceux | celles | - -- 近称と遠称を区別したいときには、それぞれの後ろに-ci(近称)や-là(遠称)をつける。 diff --git a/app/learn/french/13/page.mdx b/app/learn/french/13/page.mdx deleted file mode 100644 index fbfd347..0000000 --- a/app/learn/french/13/page.mdx +++ /dev/null @@ -1,20 +0,0 @@ -export const title = "主な否定表現"; - -# 主な否定表現 - -_第4章 否定文と疑問文より_ - -| 表現 | 意味 | 例文 | -| ------------- | ------------ | ---------------------------------------- | -| ne~plus | もう〜ない | Je n'habite plus à Lyon. | -| ne~jamais | 決して〜ない | Je ne travaille jamais le samedi. | -| ne~rien | 何も〜ない | Ce n'est rien. | -| ne~personne | 誰も〜ない | Il n'y a personne. | -| ne~ni A ni B | AもBも〜ない | Je ne parle ni l'anglais ni le japonais. | - -## 疑問詞のない疑問文への答え方 - -- 肯定疑問文:Oui(はい)/Non(いいえ) -- 否定疑問文:Si(いいえ)/Non(はい) - -「si」は否定文への、「non」は肯定文への付加疑問文の付加要素としても同様に作用する。 diff --git a/app/learn/french/14/page.mdx b/app/learn/french/14/page.mdx deleted file mode 100644 index 8b54b0c..0000000 --- a/app/learn/french/14/page.mdx +++ /dev/null @@ -1,22 +0,0 @@ -export const title = "疑問詞一覧"; - -# 疑問詞一覧 - -_第4章 否定文と疑問文より_ - -| 疑問詞 | 意味 | 例文 | -| -------- | ------ | ---------------------------------------- | -| qui | 誰 | Qui est là ? | -| que | 何 | Qu'est-ce que c'est ? | -| quand | いつ | Quand allez-vous au Japon ? | -| où | どこ | Où habites-tu ? | -| combien | いくつ | Combien d'enfants avez-vous ? | -| pourquoi | なぜ | Pourquoi pleures-tu ? | -| comment | どう | Comment allez-vous ? | -| quel | どの | Quelle voiture avez-vous achetée ? | -| lequel | どれ | Laquelle de ces voitures préférez-vous ? | -| quoi | 何 | Avec quoi mangez-vous ce plat ? | - -- quelとlequelは性数変化する。 -- quoiは前置詞の目的語部分を質問するときに使う。 -- 間接疑問文の場合「何が」は「ce qui」に、「何を」は「ce que」になる。 diff --git a/app/learn/french/15/page.mdx b/app/learn/french/15/page.mdx deleted file mode 100644 index 26b7df1..0000000 --- a/app/learn/french/15/page.mdx +++ /dev/null @@ -1,22 +0,0 @@ -export const title = "命令形の不規則活用"; - -# 命令形の不規則活用 - -_第5章 命令文より_ - -大半の動詞は直説法現在形と同型で命令形を作るが、以下の動詞は接続法の語形を元に命令形を作る。 - -| | 二人称単数命令形 | 二人称複数命令形 | 一人称複数命令形 | -| ------- | ---------------- | ---------------- | ---------------- | -| être | sois | soyez | soyons | -| avoir | aie | ayez | ayons | -| savoir | sache | sachez | sachons | -| vouloir | veuille | veuillez | veuillons | - -- veuilleとveuillonsについてはほとんど使用されない。 -- Ayez du courage ! (元気を出してください。) -- Soyez patient ! (我慢してください。) - -肯定命令文において人称代名詞をつける場合は、動詞の後ろにおいてハイフンで結ぶ(この場合、人称代名詞は強勢形になる)。 - -- Excusez-moi. diff --git a/app/learn/french/16/page.mdx b/app/learn/french/16/page.mdx deleted file mode 100644 index 6fed985..0000000 --- a/app/learn/french/16/page.mdx +++ /dev/null @@ -1,16 +0,0 @@ -export const title = "直説法半過去形の活用"; - -# 直説法半過去形の活用 - -_第6章 時制より_ - -語幹は直説法現在形の一人称複数形の語幹と同じ(êtreだけ例外でét-)。 - -| 人称 | 語尾 | 例(donner) | -| ---------- | ------ | ------------ | -| 一人称単数 | -ais | donnais | -| 二人称単数 | -ais | donnais | -| 三人称単数 | -ait | donnait | -| 一人称複数 | -ions | donnions | -| 二人称複数 | -iez | donniez | -| 三人称複数 | -aient | donnaient | diff --git a/app/learn/french/17/page.mdx b/app/learn/french/17/page.mdx deleted file mode 100644 index 1416eba..0000000 --- a/app/learn/french/17/page.mdx +++ /dev/null @@ -1,20 +0,0 @@ -export const title = "直説法単純未来形の活用"; - -# 直説法単純未来形の活用 - -_第6章 時制より_ - -語幹の作り方: - -- -er動詞:原型からrをとったものを語幹にする -- -ir動詞:原型からrをとったものを語幹にする -- reで終わる動詞:原型からreを取り除いたものを語幹にする - -| 人称 | 語尾 | 例(donner) | 例(finir) | 例(être) | 例(avoir) | -| ---------- | -------- | ------------ | ----------- | ---------- | ----------- | -| 一人称単数 | -(e)rai | donnerai | finirai | serai | aurai | -| 二人称単数 | -(e)ras | donneras | finiras | seras | auras | -| 三人称単数 | -(e)ra | donnera | finira | sera | aura | -| 一人称複数 | -(e)rons | donnerons | finirons | serons | aurons | -| 二人称複数 | -(e)rez | donnerez | finirez | serez | aurez | -| 三人称複数 | -(e)ront | donneront | finiront | seront | auront | diff --git a/app/learn/french/18/page.mdx b/app/learn/french/18/page.mdx deleted file mode 100644 index 8a9d7cb..0000000 --- a/app/learn/french/18/page.mdx +++ /dev/null @@ -1,10 +0,0 @@ -export const title = "比較級で特殊な変化をする形容詞・副詞"; - -# 比較級で特殊な変化をする形容詞・副詞 - -_第8章 比較より_ - -- bonの優等比較級:meilleur(×plus bon) -- bienの優等比較級:mieux(×plus bien) -- mauvaisの優等比較級:pire(×plus mauvais) -- petitの優等比較級:moindre(×plus petit) diff --git a/app/learn/french/19/page.mdx b/app/learn/french/19/page.mdx deleted file mode 100644 index 8821a82..0000000 --- a/app/learn/french/19/page.mdx +++ /dev/null @@ -1,20 +0,0 @@ -export const title = "現在分詞・過去分詞の作り方"; - -# 現在分詞・過去分詞の作り方 - -_第10章 分詞より_ - -## 現在分詞 - -動詞の1人称複数形の語幹に、-antを付ける。 - -- parler → parlant - -例外:être → étant、avoir → ayant、savoir → sachant - -## 過去分詞 - -- er動詞:語尾をéにする(manger → mangé) -- ir動詞:語尾をiにする(finir → fini) -- être → été -- avoir → eu diff --git a/app/learn/french/20/page.mdx b/app/learn/french/20/page.mdx deleted file mode 100644 index a342929..0000000 --- a/app/learn/french/20/page.mdx +++ /dev/null @@ -1,18 +0,0 @@ -export const title = "条件法現在形の活用"; - -# 条件法現在形の活用 - -_第11章 条件法より_ - -作り方:「単純未来形の前半部分(rまで)+半過去形の語尾」 - -| 人称 | 例(donner) | 例(finir) | 例(être) | 例(avoir) | 例(faire) | -| ---------- | ------------ | ----------- | ---------- | ----------- | ----------- | -| 一人称単数 | donnerais | finirais | serais | aurais | ferais | -| 二人称単数 | donnerais | finirais | serais | aurais | ferais | -| 三人称単数 | donnerait | finirait | serait | aurait | ferait | -| 一人称複数 | donnerions | finirions | serions | aurions | ferions | -| 二人称複数 | donneriez | finiriez | seriez | auriez | feriez | -| 三人称複数 | donneraient | finiraient | seraient | auraient | feraient | - -- 条件法過去形は「avoir(être)の条件法現在形+動詞の過去分詞形」で作成可能。 diff --git a/app/learn/french/21/page.mdx b/app/learn/french/21/page.mdx deleted file mode 100644 index e017fd7..0000000 --- a/app/learn/french/21/page.mdx +++ /dev/null @@ -1,17 +0,0 @@ -export const title = "接続法現在形の活用"; - -# 接続法現在形の活用 - -_第12章 接続法より_ - -| 人称 | 語幹 | 語尾 | 特殊形(être) | 特殊形(avoir) | -| ---------- | ------------------------------------ | ----- | -------------- | --------------- | -| 一人称単数 | 直説法現在形3人称複数形の語幹と同様 | -e | sois | aie | -| 二人称単数 | 直説法現在形3人称複数形の語幹と同様 | -es | sois | aies | -| 三人称単数 | 直説法現在形3人称複数形の語幹と同様 | -e | soit | ait | -| 一人称複数 | 直説法現在形1人称複数形の語幹と同様 | -ions | soyons | ayons | -| 二人称複数 | 直説法現在形1人称複数形の語幹と同様 | -iez | soyez | ayez | -| 三人称複数 | 直説法現在形3人称複数形の語幹と同様 | -ent | soient | aient | - -- 語幹は不規則でこの通りにならないものもあるが、語尾は規則的である。 -- 単数形と三人称複数形の語尾は直説法現在形と同じで、一人称複数、二人称複数の語尾は半過去形と同じである。 diff --git a/app/learn/french/22/page.mdx b/app/learn/french/22/page.mdx deleted file mode 100644 index 3471559..0000000 --- a/app/learn/french/22/page.mdx +++ /dev/null @@ -1,23 +0,0 @@ -export const title = "不定表現一覧"; - -# 不定表現一覧 - -_第13章 不定表現より_ - -| 不定表現 | 意味 | 補足 | -| --------- | ---------------------------- | ------------------------------------------------------------------------ | -| aucun | いかなる(〜ない) | 否定文で用いられる/原則単数名詞を修飾する/pasと共には使えない | -| quelque | いくつかの、いくらかの/ある | 前者は可算複数形または不可算名詞、後者は可算単数形または不可算名詞を伴う | -| n'importe | 〜でも(よい) | 後ろには疑問詞が続く | -| chaque | それぞれの | 不定形容詞であり、複数形は存在しない | -| chacun | それぞれの | 不定代名詞であり、複数形は存在しない | -| tout | すべての | 後ろに定冠詞付きの名詞を伴ってそれを修飾する | - -- Il n'y a aucune solution à ce problème. -- J'ai encore quelques questions à vous poser. -- Il a montré quelque intérêt pour ce projet. -- Vous pouvez appeler n'importe quand, je suis disponible. -- Choisissez n'importe quel livre, ils sont tous intéressants. -- Chaque étudiant doit rendre son devoir avant vendredi. -- J'ai distribué des cartes : une pour chacun. -- Toutes les fenêtres doivent rester fermées. diff --git a/app/learn/french/23/page.mdx b/app/learn/french/23/page.mdx deleted file mode 100644 index eab63d7..0000000 --- a/app/learn/french/23/page.mdx +++ /dev/null @@ -1,17 +0,0 @@ -export const title = "中性代名詞一覧"; - -# 中性代名詞一覧 - -_第16章 中性代名詞より_ - -中性代名詞は「性数一致しない代名詞」のこと。 - -| 中性代名詞 | 指示対象 | 例文 | -| ---------- | -------------------------- | ------------------------------------------------------------------------------------------------- | -| en | 前置詞「de」+定名詞(句) | J'en viens.(私はそこから来ました。) | -| en | 同類を表す不定名詞(句) | Avez-vous des amis ? -Oui, j'en ai.(あなたは友達がいますか。-はい、います。) | -| y | 前置詞「à」+定名詞(句) | On y compare la vie.(人生はそれにたとえられる。) | -| le | 文脈全体 | Je lui ai téléphoné. -Je l'ai fait par précaution.(私は彼に電話をした。-私は念のためそうした。) | -| le | 形容詞 | Êtes-vous fatigué ? -Oui, je le suis.(あなたは疲れていますか。-はい、疲れています。) | - -- enが同類を表す不定名詞(句)を置き換える場合で、後ろに形容詞が付いている場合は、形容詞は「de+形容詞」の形で残る。 diff --git a/app/learn/german/02/page.mdx b/app/learn/german/02/page.mdx deleted file mode 100644 index f01e9cb..0000000 --- a/app/learn/german/02/page.mdx +++ /dev/null @@ -1,12 +0,0 @@ -export const title = "名詞の性の語尾による判別"; - -# 名詞の性の語尾による判別 - -_第1章 品詞と文型より_ - -ものの名詞は男性・女性を直観的に判断できないため、語尾によってある程度判別する。(例外もある) - -| 語尾 | 性 | -| ------------------------------- | -------- | -| -age、-ment、-eau、-teur | 男性名詞 | -| -tion、-sion、-té、-esse、-ette | 女性名詞 | diff --git a/app/learn/german/02/page.tsx b/app/learn/german/02/page.tsx new file mode 100644 index 0000000..6095a45 --- /dev/null +++ b/app/learn/german/02/page.tsx @@ -0,0 +1,19 @@ +"use client"; + +import { TranslationPractice } from "@/components/translation/TranslationPractice"; + +export const title = "翻訳"; + +export default function GermanTranslationPage() { + return ( +
+

翻訳

+

+ ドイツ語⇔日本語の訳文を書き、AIに添削してもらいましょう。 +

+
+ +
+
+ ); +} diff --git a/app/learn/spanish/02/page.mdx b/app/learn/spanish/02/page.mdx deleted file mode 100644 index 3d3f536..0000000 --- a/app/learn/spanish/02/page.mdx +++ /dev/null @@ -1,51 +0,0 @@ -import SpanishNumberPracticeLoader from "@/components/spanish/SpanishNumberPracticeLoader"; - -export const title = "数字タイピング演習"; - -# 数字タイピング演習 - - - -{/* 出題データ定義テーブル (display:none) */} - - diff --git a/app/learn/spanish/02/page.tsx b/app/learn/spanish/02/page.tsx index 163113e..3bd940f 100644 --- a/app/learn/spanish/02/page.tsx +++ b/app/learn/spanish/02/page.tsx @@ -1,18 +1,18 @@ "use client"; -import { ConjugationPractice } from "@/components/verbs/ConjugationPractice"; -import { spanishConjugationConfig } from "@/lib/conjugation/es/config"; -import { verbs } from "./verbs"; +import { TranslationPractice } from "@/components/translation/TranslationPractice"; -export const title = "動詞の活用"; +export const title = "翻訳"; -export default function SpanishVerbConjugationPage() { +export default function SpanishTranslationPage() { return (
-

動詞の活用

-

動詞・時制・法を選んで、活用形を入力しながら覚えましょう。

+

翻訳

+

+ スペイン語⇔日本語の訳文を書き、AIに添削してもらいましょう。 +

- +
); diff --git a/app/learn/spanish/03/page.mdx b/app/learn/spanish/03/page.mdx index 6c31ae1..3d3f536 100644 --- a/app/learn/spanish/03/page.mdx +++ b/app/learn/spanish/03/page.mdx @@ -1,67 +1,51 @@ -import SpanishTablePracticeLoader from "@/components/spanish/SpanishTablePracticeLoader"; +import SpanishNumberPracticeLoader from "@/components/spanish/SpanishNumberPracticeLoader"; -export const title = "人称代名詞・冠詞・指示詞の表完成演習"; +export const title = "数字タイピング演習"; -# 人称代名詞・冠詞・指示詞の表完成演習 +# 数字タイピング演習 - + {/* 出題データ定義テーブル (display:none) */} diff --git a/app/learn/spanish/03/page.tsx b/app/learn/spanish/03/page.tsx new file mode 100644 index 0000000..163113e --- /dev/null +++ b/app/learn/spanish/03/page.tsx @@ -0,0 +1,19 @@ +"use client"; + +import { ConjugationPractice } from "@/components/verbs/ConjugationPractice"; +import { spanishConjugationConfig } from "@/lib/conjugation/es/config"; +import { verbs } from "./verbs"; + +export const title = "動詞の活用"; + +export default function SpanishVerbConjugationPage() { + return ( +
+

動詞の活用

+

動詞・時制・法を選んで、活用形を入力しながら覚えましょう。

+
+ +
+
+ ); +} diff --git a/app/learn/spanish/02/verbs.ts b/app/learn/spanish/03/verbs.ts similarity index 100% rename from app/learn/spanish/02/verbs.ts rename to app/learn/spanish/03/verbs.ts diff --git a/app/learn/spanish/04/page.mdx b/app/learn/spanish/04/page.mdx index c16bc0f..6c31ae1 100644 --- a/app/learn/spanish/04/page.mdx +++ b/app/learn/spanish/04/page.mdx @@ -1,44 +1,67 @@ -import SpanishFillInPracticeLoader from "@/components/spanish/SpanishFillInPracticeLoader"; +import SpanishTablePracticeLoader from "@/components/spanish/SpanishTablePracticeLoader"; -{/* セクションタイトルの定義(サイドバーや一覧ページで自動取得・表示される) */} -export const title = "紛らわしい文法(ser/estar・点過去/線過去)穴埋め演習"; +export const title = "人称代名詞・冠詞・指示詞の表完成演習"; -# 紛らわしい文法(ser/estar・点過去/線過去)穴埋め演習 +# 人称代名詞・冠詞・指示詞の表完成演習 -{/* 穴埋め演習用コンポーネントの読み込み */} + - +{/* 出題データ定義テーブル (display:none) */} diff --git a/app/learn/spanish/05/page.mdx b/app/learn/spanish/05/page.mdx new file mode 100644 index 0000000..c16bc0f --- /dev/null +++ b/app/learn/spanish/05/page.mdx @@ -0,0 +1,44 @@ +import SpanishFillInPracticeLoader from "@/components/spanish/SpanishFillInPracticeLoader"; + +{/* セクションタイトルの定義(サイドバーや一覧ページで自動取得・表示される) */} +export const title = "紛らわしい文法(ser/estar・点過去/線過去)穴埋め演習"; + +# 紛らわしい文法(ser/estar・点過去/線過去)穴埋め演習 + +{/* 穴埋め演習用コンポーネントの読み込み */} + + + + diff --git a/components/pinyin/PinyinPractice.tsx b/components/pinyin/PinyinPractice.tsx index 5f8cb21..c4b43d5 100644 --- a/components/pinyin/PinyinPractice.tsx +++ b/components/pinyin/PinyinPractice.tsx @@ -3,7 +3,7 @@ import { useEffect, useMemo, useState } from "react"; import { AccentInput } from "@/components/verbs/AccentInput"; import { speak } from "@/lib/speech"; -import type { HanziEntry } from "@/app/learn/chinese/02/characters"; +import type { HanziEntry } from "@/app/learn/chinese/03/characters"; // 母音ごとの声調サイクル。母音を入力した直後に ↑/↓ キーで // 第1声→第2声→第3声→第4声(→軽声)と切り替えられる。 diff --git a/components/spanish/SpanishFillInPracticeLoader.tsx b/components/spanish/SpanishFillInPracticeLoader.tsx index b2df466..2934e7e 100644 --- a/components/spanish/SpanishFillInPracticeLoader.tsx +++ b/components/spanish/SpanishFillInPracticeLoader.tsx @@ -3,12 +3,12 @@ import path from "node:path"; import SpanishFillInPractice, { type FillInQuestionItem } from "./SpanishFillInPractice"; /** - * MDX教材ファイル(app/learn/spanish/04/page.mdx)から + * MDX教材ファイル(app/learn/spanish/05/page.mdx)から * 穴埋め文法問題データを動的に抽出する関数。 * データのベタ打ちを排除し、教材ファイルを唯一のデータソースとして使用する。 */ async function getFillInQuestionsFromMdx(): Promise { - const filePath = path.join(process.cwd(), "app", "learn", "spanish", "04", "page.mdx"); + const filePath = path.join(process.cwd(), "app", "learn", "spanish", "05", "page.mdx"); const items: FillInQuestionItem[] = []; try { diff --git a/components/spanish/SpanishTablePracticeLoader.tsx b/components/spanish/SpanishTablePracticeLoader.tsx index 46ce81a..4fc160d 100644 --- a/components/spanish/SpanishTablePracticeLoader.tsx +++ b/components/spanish/SpanishTablePracticeLoader.tsx @@ -22,12 +22,12 @@ function mergeAdjacentCells(cells: string[]): GrammarTableCell[] { } /** - * MDX教材ファイル(app/learn/spanish/03/page.mdx)から + * MDX教材ファイル(app/learn/spanish/04/page.mdx)から * 人称代名詞・冠詞・指示詞の各文法表データを動的に抽出する関数。 * データのベタ打ちを排除し、教材ファイルを唯一のデータソースとして使用する。 */ async function getGrammarTablesFromMdx(): Promise { - const filePath = path.join(process.cwd(), "app", "learn", "spanish", "03", "page.mdx"); + const filePath = path.join(process.cwd(), "app", "learn", "spanish", "04", "page.mdx"); const tables: GrammarTableData[] = []; try { diff --git a/components/translation/TranslationPractice.tsx b/components/translation/TranslationPractice.tsx new file mode 100644 index 0000000..e672220 --- /dev/null +++ b/components/translation/TranslationPractice.tsx @@ -0,0 +1,530 @@ +"use client"; + +import { useEffect, useMemo, useState, useTransition } from "react"; +import Link from "next/link"; +import { usePathname } from "next/navigation"; + +import { getTranslationHistory, submitTranslation } from "@/lib/translation/actions"; +import { getTranslationLevels, getTranslationProblems } from "@/lib/translation/problems"; +import { + CUSTOM_SOURCE_MAX_LENGTH, + TRANSLATION_SCORE_DEFAULT, + TRANSLATION_SCORE_OPTIONS, + type TranslationDirection, + type TranslationProblemSource, + type TranslationSubmissionDTO, +} from "@/lib/translation/types"; + +interface ResolvedProblem { + source: TranslationProblemSource; + problemId?: string; + level: string; + direction: TranslationDirection; + sourceText: string; + referenceTranslation: string | null; +} + +interface TranslationPracticeProps { + languageSlug: string; + languageLabel: string; +} + +function directionLabel(direction: TranslationDirection, languageLabel: string): string { + return direction === "fromJapanese" ? `日本語 → ${languageLabel}` : `${languageLabel} → 日本語`; +} + +const dateFormatter = new Intl.DateTimeFormat("ja-JP", { + dateStyle: "medium", + timeStyle: "short", +}); + +export function TranslationPractice({ languageSlug, languageLabel }: TranslationPracticeProps) { + const problems = getTranslationProblems(languageSlug); + const levels = useMemo(() => getTranslationLevels(languageSlug), [languageSlug]); + + const [status, setStatus] = useState<"loading" | "guest" | "ready">("loading"); + const [phase, setPhase] = useState<"settings" | "writing" | "result">("settings"); + const [level, setLevel] = useState(levels[0] ?? ""); + const [direction, setDirection] = useState("fromJapanese"); + const [problemSource, setProblemSource] = useState("preset"); + const [scoreMax, setScoreMax] = useState(TRANSLATION_SCORE_DEFAULT); + + const problemsForSelection = useMemo( + () => problems.filter((p) => p.level === level && p.direction === direction), + [problems, level, direction], + ); + const [selectedProblemId, setSelectedProblemId] = useState(problemsForSelection[0]?.id ?? ""); + const [customSourceText, setCustomSourceText] = useState(""); + + const [activeProblem, setActiveProblem] = useState(null); + const [content, setContent] = useState(""); + const [error, setError] = useState(null); + const [pending, startTransition] = useTransition(); + const [lastSubmission, setLastSubmission] = useState(null); + const [history, setHistory] = useState([]); + const [expandedHistoryId, setExpandedHistoryId] = useState(null); + + useEffect(() => { + let cancelled = false; + getTranslationHistory(languageSlug).then((result) => { + if (cancelled) return; + setHistory(result.submissions); + setStatus(result.isLoggedIn ? "ready" : "guest"); + }); + return () => { + cancelled = true; + }; + }, [languageSlug]); + + const selectLevel = (nextLevel: string) => { + setLevel(nextLevel); + const nextProblems = problems.filter((p) => p.level === nextLevel && p.direction === direction); + setSelectedProblemId(nextProblems[0]?.id ?? ""); + }; + + const selectDirection = (nextDirection: TranslationDirection) => { + setDirection(nextDirection); + const nextProblems = problems.filter((p) => p.level === level && p.direction === nextDirection); + setSelectedProblemId(nextProblems[0]?.id ?? ""); + }; + + const canStart = + problemSource === "preset" ? selectedProblemId !== "" : customSourceText.trim() !== ""; + + const startWriting = () => { + if (problemSource === "preset") { + const problem = problemsForSelection.find((p) => p.id === selectedProblemId); + if (!problem) return; + setActiveProblem({ + source: "preset", + problemId: problem.id, + level: problem.level, + direction: problem.direction, + sourceText: problem.sourceText, + referenceTranslation: problem.referenceTranslation, + }); + } else { + const sourceText = customSourceText.trim(); + if (!sourceText) return; + setActiveProblem({ + source: "custom", + level, + direction, + sourceText, + referenceTranslation: null, + }); + } + setContent(""); + setError(null); + setLastSubmission(null); + setPhase("writing"); + }; + + const backToSettings = () => { + setPhase("settings"); + }; + + const handleSubmit = () => { + if (!activeProblem || pending) return; + if (!content.trim()) { + setError("訳文を入力してください。"); + return; + } + setError(null); + + startTransition(async () => { + const result = await submitTranslation({ + language: languageSlug, + problemSource: activeProblem.source, + problemId: activeProblem.source === "preset" ? activeProblem.problemId : undefined, + direction: activeProblem.source === "custom" ? activeProblem.direction : undefined, + level: activeProblem.source === "custom" ? activeProblem.level : undefined, + customSourceText: activeProblem.source === "custom" ? activeProblem.sourceText : undefined, + content, + scoreMax, + }); + + if ("error" in result) { + setError(result.error); + return; + } + + setLastSubmission(result.submission); + setHistory((prev) => [result.submission, ...prev]); + setPhase("result"); + }); + }; + + if (status === "loading") { + return
読み込み中…
; + } + + if (status === "guest") { + return ; + } + + return ( +
+ {phase === "settings" && ( + <> +
+
+
+ {levels.map((l) => ( + + ))} + {levels.length === 0 && ( +

+ この言語にはまだ級が用意されていません。 +

+ )} +
+
+ +
+
訳す方向
+
+ + +
+
+ +
+
題材
+
+ + +
+ + {problemSource === "preset" ? ( +
+ {problemsForSelection.map((problem) => ( + + ))} + {problemsForSelection.length === 0 && ( +

+ この級・方向の問題はまだ用意されていません。「自分で題材を用意する」から始めてください。 +

+ )} +
+ ) : ( +
+ +