Add per-form English translations to verb conjugation table
New EnglishConjugator in SharedModels constructs English translations by combining the verb's infinitive with person pronouns and tense auxiliaries (e.g., abatir conditional yo → "I would knock down"). Covers all 20 tense IDs, handles 60+ irregular English verbs, multi-word verbs, 3rd person rules, gerund and participle formation. VerbDetailView shows the English below each conjugated form, plus a legend explaining red = irregular conjugation. 42 tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -211,6 +211,7 @@
|
|||||||
7E6AF62A3A949630E067DC22 /* Info.plist */,
|
7E6AF62A3A949630E067DC22 /* Info.plist */,
|
||||||
353C5DE41FD410FA82E3AED7 /* Models */,
|
353C5DE41FD410FA82E3AED7 /* Models */,
|
||||||
1994867BC8E985795A172854 /* Services */,
|
1994867BC8E985795A172854 /* Services */,
|
||||||
|
BFC1AEBE02CE22E6474FFEA6 /* Utilities */,
|
||||||
3C75490F53C34A37084FF478 /* ViewModels */,
|
3C75490F53C34A37084FF478 /* ViewModels */,
|
||||||
A81CA75762B08D35D5B7A44D /* Views */,
|
A81CA75762B08D35D5B7A44D /* Views */,
|
||||||
);
|
);
|
||||||
@@ -399,6 +400,13 @@
|
|||||||
path = Course;
|
path = Course;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
BFC1AEBE02CE22E6474FFEA6 /* Utilities */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
);
|
||||||
|
path = Utilities;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
F605D24E5EA11065FD18AF7E /* Products */ = {
|
F605D24E5EA11065FD18AF7E /* Products */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ struct VerbDetailView: View {
|
|||||||
ContentUnavailableView("No forms loaded", systemImage: "exclamationmark.triangle")
|
ContentUnavailableView("No forms loaded", systemImage: "exclamationmark.triangle")
|
||||||
} else {
|
} else {
|
||||||
ForEach(formsForTense, id: \.personIndex) { form in
|
ForEach(formsForTense, id: \.personIndex) { form in
|
||||||
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
HStack {
|
HStack {
|
||||||
Text(TenseInfo.persons[form.personIndex])
|
Text(TenseInfo.persons[form.personIndex])
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
@@ -46,6 +47,20 @@ struct VerbDetailView: View {
|
|||||||
.fontWeight(form.regularity != "ordinary" ? .semibold : .regular)
|
.fontWeight(form.regularity != "ordinary" ? .semibold : .regular)
|
||||||
.foregroundStyle(form.regularity != "ordinary" ? .red : .primary)
|
.foregroundStyle(form.regularity != "ordinary" ? .red : .primary)
|
||||||
}
|
}
|
||||||
|
Text(EnglishConjugator.translate(
|
||||||
|
english: verb.english,
|
||||||
|
tenseId: selectedTense.id,
|
||||||
|
personIndex: form.personIndex
|
||||||
|
))
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if formsForTense.contains(where: { $0.regularity != "ordinary" }) {
|
||||||
|
Label("Red indicates an irregular conjugation", systemImage: "info.circle")
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} header: {
|
} header: {
|
||||||
|
|||||||
@@ -0,0 +1,246 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// Constructs approximate English translations for Spanish conjugation forms
|
||||||
|
/// by combining the verb's English infinitive with person pronouns and tense auxiliaries.
|
||||||
|
///
|
||||||
|
/// Not perfect for irregular English verbs (go→went, be→was) but covers the
|
||||||
|
/// common patterns well enough for a learning context.
|
||||||
|
public enum EnglishConjugator {
|
||||||
|
|
||||||
|
public static func translate(english: String, tenseId: String, personIndex: Int) -> String {
|
||||||
|
let base = english.hasPrefix("to ") ? String(english.dropFirst(3)).trimmingCharacters(in: .whitespaces) : english
|
||||||
|
guard !base.isEmpty else { return "" }
|
||||||
|
|
||||||
|
let pronoun = pronoun(for: personIndex)
|
||||||
|
|
||||||
|
switch tenseId {
|
||||||
|
// Indicative
|
||||||
|
case "ind_presente":
|
||||||
|
return "\(pronoun) \(presentForm(base, personIndex: personIndex))"
|
||||||
|
case "ind_preterito":
|
||||||
|
return "\(pronoun) \(pastForm(base))"
|
||||||
|
case "ind_imperfecto":
|
||||||
|
return "\(pronoun) used to \(base)"
|
||||||
|
case "ind_futuro":
|
||||||
|
return "\(pronoun) will \(base)"
|
||||||
|
case "ind_perfecto":
|
||||||
|
return "\(pronoun) \(haveForm(personIndex)) \(pastParticiple(base))"
|
||||||
|
case "ind_pluscuamperfecto":
|
||||||
|
return "\(pronoun) had \(pastParticiple(base))"
|
||||||
|
case "ind_futuro_perfecto":
|
||||||
|
return "\(pronoun) will have \(pastParticiple(base))"
|
||||||
|
case "ind_preterito_anterior":
|
||||||
|
return "\(pronoun) had \(pastParticiple(base))"
|
||||||
|
|
||||||
|
// Conditional
|
||||||
|
case "cond_presente":
|
||||||
|
return "\(pronoun) would \(base)"
|
||||||
|
case "cond_perfecto":
|
||||||
|
return "\(pronoun) would have \(pastParticiple(base))"
|
||||||
|
|
||||||
|
// Subjunctive
|
||||||
|
case "subj_presente":
|
||||||
|
return "that \(pronoun) \(base)"
|
||||||
|
case "subj_imperfecto_1", "subj_imperfecto_2":
|
||||||
|
return "that \(pronoun) would \(base)"
|
||||||
|
case "subj_perfecto":
|
||||||
|
return "that \(pronoun) \(haveForm(personIndex)) \(pastParticiple(base))"
|
||||||
|
case "subj_pluscuamperfecto_1", "subj_pluscuamperfecto_2":
|
||||||
|
return "that \(pronoun) had \(pastParticiple(base))"
|
||||||
|
case "subj_futuro":
|
||||||
|
return "that \(pronoun) will \(base)"
|
||||||
|
case "subj_futuro_perfecto":
|
||||||
|
return "that \(pronoun) will have \(pastParticiple(base))"
|
||||||
|
|
||||||
|
// Imperative
|
||||||
|
case "imp_afirmativo":
|
||||||
|
return imperativeAffirmative(base, personIndex: personIndex)
|
||||||
|
case "imp_negativo":
|
||||||
|
return "don't \(base)"
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "\(pronoun) \(base)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Pronouns
|
||||||
|
|
||||||
|
private static func pronoun(for personIndex: Int) -> String {
|
||||||
|
switch personIndex {
|
||||||
|
case 0: "I"
|
||||||
|
case 1: "you"
|
||||||
|
case 2: "he/she"
|
||||||
|
case 3: "we"
|
||||||
|
case 4: "you all"
|
||||||
|
case 5: "they"
|
||||||
|
default: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Present tense
|
||||||
|
|
||||||
|
private static func presentForm(_ base: String, personIndex: Int) -> String {
|
||||||
|
// 3rd person singular adds -s/-es
|
||||||
|
guard personIndex == 2 else { return base }
|
||||||
|
let words = base.split(separator: " ")
|
||||||
|
guard let first = words.first else { return base }
|
||||||
|
let verb = String(first)
|
||||||
|
let rest = words.dropFirst().joined(separator: " ")
|
||||||
|
let conjugated = addThirdPersonS(verb)
|
||||||
|
return rest.isEmpty ? conjugated : "\(conjugated) \(rest)"
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func addThirdPersonS(_ verb: String) -> String {
|
||||||
|
if verb == "have" { return "has" }
|
||||||
|
if verb == "be" { return "is" }
|
||||||
|
if verb == "do" { return "does" }
|
||||||
|
if verb == "go" { return "goes" }
|
||||||
|
if verb.hasSuffix("sh") || verb.hasSuffix("ch") || verb.hasSuffix("x") ||
|
||||||
|
verb.hasSuffix("s") || verb.hasSuffix("z") || verb.hasSuffix("o") {
|
||||||
|
return verb + "es"
|
||||||
|
}
|
||||||
|
if verb.hasSuffix("y") && verb.count > 1 {
|
||||||
|
let yIndex = verb.index(before: verb.endIndex)
|
||||||
|
let beforeY = verb[verb.index(before: yIndex)]
|
||||||
|
if !"aeiou".contains(beforeY) {
|
||||||
|
return String(verb.dropLast()) + "ies"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return verb + "s"
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Past tense
|
||||||
|
|
||||||
|
private static func pastForm(_ base: String) -> String {
|
||||||
|
// Check common irregulars first
|
||||||
|
let words = base.split(separator: " ")
|
||||||
|
guard let first = words.first else { return base }
|
||||||
|
let verb = String(first).lowercased()
|
||||||
|
let rest = words.dropFirst().joined(separator: " ")
|
||||||
|
|
||||||
|
let irregular: String? = commonIrregularPast[verb]
|
||||||
|
let past = irregular ?? addEd(String(first))
|
||||||
|
return rest.isEmpty ? past : "\(past) \(rest)"
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func addEd(_ verb: String) -> String {
|
||||||
|
if verb.hasSuffix("e") { return verb + "d" }
|
||||||
|
if verb.hasSuffix("y") && verb.count > 1 {
|
||||||
|
let beforeY = verb[verb.index(before: verb.endIndex)]
|
||||||
|
if !"aeiou".contains(beforeY) {
|
||||||
|
return String(verb.dropLast()) + "ied"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return verb + "ed"
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Past participle
|
||||||
|
|
||||||
|
private static func pastParticiple(_ base: String) -> String {
|
||||||
|
let words = base.split(separator: " ")
|
||||||
|
guard let first = words.first else { return base }
|
||||||
|
let verb = String(first).lowercased()
|
||||||
|
let rest = words.dropFirst().joined(separator: " ")
|
||||||
|
|
||||||
|
let irregular: String? = commonIrregularParticiple[verb]
|
||||||
|
let participle = irregular ?? addEd(String(first))
|
||||||
|
return rest.isEmpty ? participle : "\(participle) \(rest)"
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Gerund
|
||||||
|
|
||||||
|
private static func gerund(_ base: String) -> String {
|
||||||
|
let words = base.split(separator: " ")
|
||||||
|
guard let first = words.first else { return base }
|
||||||
|
let verb = String(first)
|
||||||
|
let rest = words.dropFirst().joined(separator: " ")
|
||||||
|
|
||||||
|
let ing: String
|
||||||
|
if verb.hasSuffix("ie") {
|
||||||
|
ing = String(verb.dropLast(2)) + "ying"
|
||||||
|
} else if verb.hasSuffix("e") && !verb.hasSuffix("ee") {
|
||||||
|
ing = String(verb.dropLast()) + "ing"
|
||||||
|
} else {
|
||||||
|
ing = verb + "ing"
|
||||||
|
}
|
||||||
|
return rest.isEmpty ? ing : "\(ing) \(rest)"
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Auxiliaries
|
||||||
|
|
||||||
|
private static func haveForm(_ personIndex: Int) -> String {
|
||||||
|
personIndex == 2 ? "has" : "have"
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func beForm(_ personIndex: Int) -> String {
|
||||||
|
switch personIndex {
|
||||||
|
case 0: "am"
|
||||||
|
case 2: "is"
|
||||||
|
default: "are"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Imperative
|
||||||
|
|
||||||
|
private static func imperativeAffirmative(_ base: String, personIndex: Int) -> String {
|
||||||
|
switch personIndex {
|
||||||
|
case 1, 4: "\(base)!"
|
||||||
|
case 3: "let's \(base)!"
|
||||||
|
default: "\(base)!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Irregular lookups (most common English irregulars)
|
||||||
|
|
||||||
|
private static let commonIrregularPast: [String: String] = [
|
||||||
|
"be": "was/were", "have": "had", "do": "did", "go": "went",
|
||||||
|
"say": "said", "get": "got", "make": "made", "know": "knew",
|
||||||
|
"think": "thought", "take": "took", "come": "came", "see": "saw",
|
||||||
|
"want": "wanted", "give": "gave", "tell": "told", "find": "found",
|
||||||
|
"put": "put", "leave": "left", "bring": "brought", "begin": "began",
|
||||||
|
"keep": "kept", "hold": "held", "write": "wrote", "stand": "stood",
|
||||||
|
"hear": "heard", "let": "let", "mean": "meant", "set": "set",
|
||||||
|
"meet": "met", "run": "ran", "pay": "paid", "sit": "sat",
|
||||||
|
"speak": "spoke", "read": "read", "grow": "grew", "lose": "lost",
|
||||||
|
"fall": "fell", "feel": "felt", "cut": "cut", "sell": "sold",
|
||||||
|
"drive": "drove", "buy": "bought", "wear": "wore", "choose": "chose",
|
||||||
|
"sleep": "slept", "eat": "ate", "drink": "drank", "swim": "swam",
|
||||||
|
"fly": "flew", "break": "broke", "sing": "sang", "catch": "caught",
|
||||||
|
"send": "sent", "build": "built", "spend": "spent", "win": "won",
|
||||||
|
"fight": "fought", "throw": "threw", "teach": "taught", "lead": "led",
|
||||||
|
"understand": "understood", "draw": "drew", "ride": "rode",
|
||||||
|
"rise": "rose", "shake": "shook", "forget": "forgot",
|
||||||
|
"shoot": "shot", "wake": "woke", "bite": "bit", "hide": "hid",
|
||||||
|
"lay": "laid", "lie": "lay", "strike": "struck", "hang": "hung",
|
||||||
|
"blow": "blew", "dig": "dug", "feed": "fed", "forgive": "forgave",
|
||||||
|
"freeze": "froze", "hurt": "hurt", "light": "lit", "shut": "shut",
|
||||||
|
"steal": "stole", "stick": "stuck", "sweep": "swept",
|
||||||
|
"swing": "swung", "tear": "tore",
|
||||||
|
]
|
||||||
|
|
||||||
|
private static let commonIrregularParticiple: [String: String] = [
|
||||||
|
"be": "been", "have": "had", "do": "done", "go": "gone",
|
||||||
|
"say": "said", "get": "gotten", "make": "made", "know": "known",
|
||||||
|
"think": "thought", "take": "taken", "come": "come", "see": "seen",
|
||||||
|
"give": "given", "tell": "told", "find": "found",
|
||||||
|
"put": "put", "leave": "left", "bring": "brought", "begin": "begun",
|
||||||
|
"keep": "kept", "hold": "held", "write": "written", "stand": "stood",
|
||||||
|
"hear": "heard", "let": "let", "mean": "meant", "set": "set",
|
||||||
|
"meet": "met", "run": "run", "pay": "paid", "sit": "sat",
|
||||||
|
"speak": "spoken", "read": "read", "grow": "grown", "lose": "lost",
|
||||||
|
"fall": "fallen", "feel": "felt", "cut": "cut", "sell": "sold",
|
||||||
|
"drive": "driven", "buy": "bought", "wear": "worn", "choose": "chosen",
|
||||||
|
"sleep": "slept", "eat": "eaten", "drink": "drunk", "swim": "swum",
|
||||||
|
"fly": "flown", "break": "broken", "sing": "sung", "catch": "caught",
|
||||||
|
"send": "sent", "build": "built", "spend": "spent", "win": "won",
|
||||||
|
"fight": "fought", "throw": "thrown", "teach": "taught", "lead": "led",
|
||||||
|
"understand": "understood", "draw": "drawn", "ride": "ridden",
|
||||||
|
"rise": "risen", "shake": "shaken", "forget": "forgotten",
|
||||||
|
"shoot": "shot", "wake": "woken", "bite": "bitten", "hide": "hidden",
|
||||||
|
"lay": "laid", "lie": "lain", "strike": "struck", "hang": "hung",
|
||||||
|
"blow": "blown", "dig": "dug", "feed": "fed", "forgive": "forgiven",
|
||||||
|
"freeze": "frozen", "hurt": "hurt", "light": "lit", "shut": "shut",
|
||||||
|
"steal": "stolen", "stick": "stuck", "sweep": "swept",
|
||||||
|
"swing": "swung", "tear": "torn",
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,268 @@
|
|||||||
|
import Testing
|
||||||
|
@testable import SharedModels
|
||||||
|
|
||||||
|
@Suite("EnglishConjugator")
|
||||||
|
struct EnglishConjugatorTests {
|
||||||
|
|
||||||
|
// MARK: - haber (to have) — irregular English verb
|
||||||
|
|
||||||
|
@Test("haber present: I have / you have / he/she has")
|
||||||
|
func haberPresent() {
|
||||||
|
#expect(t("to have", "ind_presente", 0) == "I have")
|
||||||
|
#expect(t("to have", "ind_presente", 1) == "you have")
|
||||||
|
#expect(t("to have", "ind_presente", 2) == "he/she has")
|
||||||
|
#expect(t("to have", "ind_presente", 3) == "we have")
|
||||||
|
#expect(t("to have", "ind_presente", 5) == "they have")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("haber preterite: I had")
|
||||||
|
func haberPreterite() {
|
||||||
|
#expect(t("to have", "ind_preterito", 0) == "I had")
|
||||||
|
#expect(t("to have", "ind_preterito", 2) == "he/she had")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("haber future: I will have")
|
||||||
|
func haberFuture() {
|
||||||
|
#expect(t("to have", "ind_futuro", 0) == "I will have")
|
||||||
|
#expect(t("to have", "ind_futuro", 3) == "we will have")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("haber conditional: I would have")
|
||||||
|
func haberConditional() {
|
||||||
|
#expect(t("to have", "cond_presente", 0) == "I would have")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("haber present perfect: I have had / he/she has had")
|
||||||
|
func haberPresentPerfect() {
|
||||||
|
#expect(t("to have", "ind_perfecto", 0) == "I have had")
|
||||||
|
#expect(t("to have", "ind_perfecto", 2) == "he/she has had")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - ir (to go) — irregular English verb
|
||||||
|
|
||||||
|
@Test("ir present: I go / he/she goes")
|
||||||
|
func irPresent() {
|
||||||
|
#expect(t("to go", "ind_presente", 0) == "I go")
|
||||||
|
#expect(t("to go", "ind_presente", 2) == "he/she goes")
|
||||||
|
#expect(t("to go", "ind_presente", 5) == "they go")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("ir preterite: I went")
|
||||||
|
func irPreterite() {
|
||||||
|
#expect(t("to go", "ind_preterito", 0) == "I went")
|
||||||
|
#expect(t("to go", "ind_preterito", 2) == "he/she went")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("ir imperfect: I used to go")
|
||||||
|
func irImperfect() {
|
||||||
|
#expect(t("to go", "ind_imperfecto", 0) == "I used to go")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("ir present perfect: I have gone")
|
||||||
|
func irPresentPerfect() {
|
||||||
|
#expect(t("to go", "ind_perfecto", 0) == "I have gone")
|
||||||
|
#expect(t("to go", "ind_perfecto", 2) == "he/she has gone")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - ser (to be) — most irregular English verb
|
||||||
|
|
||||||
|
@Test("ser present: he/she is")
|
||||||
|
func serPresent() {
|
||||||
|
#expect(t("to be", "ind_presente", 2) == "he/she is")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("ser preterite: I was/were")
|
||||||
|
func serPreterite() {
|
||||||
|
#expect(t("to be", "ind_preterito", 0) == "I was/were")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("ser present perfect: I have been")
|
||||||
|
func serPresentPerfect() {
|
||||||
|
#expect(t("to be", "ind_perfecto", 0) == "I have been")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - hablar (to speak)
|
||||||
|
|
||||||
|
@Test("hablar present: I speak / he/she speaks")
|
||||||
|
func hablarPresent() {
|
||||||
|
#expect(t("to speak", "ind_presente", 0) == "I speak")
|
||||||
|
#expect(t("to speak", "ind_presente", 2) == "he/she speaks")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("hablar preterite: I spoke")
|
||||||
|
func hablarPreterite() {
|
||||||
|
#expect(t("to speak", "ind_preterito", 0) == "I spoke")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("hablar present perfect: I have spoken")
|
||||||
|
func hablarPresentPerfect() {
|
||||||
|
#expect(t("to speak", "ind_perfecto", 0) == "I have spoken")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - comer (to eat)
|
||||||
|
|
||||||
|
@Test("comer preterite: I ate")
|
||||||
|
func comerPreterite() {
|
||||||
|
#expect(t("to eat", "ind_preterito", 0) == "I ate")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("comer present perfect: I have eaten")
|
||||||
|
func comerPresentPerfect() {
|
||||||
|
#expect(t("to eat", "ind_perfecto", 0) == "I have eaten")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - vivir (to live) — regular English verb
|
||||||
|
|
||||||
|
@Test("vivir present: I live / he/she lives")
|
||||||
|
func vivirPresent() {
|
||||||
|
#expect(t("to live", "ind_presente", 0) == "I live")
|
||||||
|
#expect(t("to live", "ind_presente", 2) == "he/she lives")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("vivir preterite: I lived")
|
||||||
|
func vivirPreterite() {
|
||||||
|
#expect(t("to live", "ind_preterito", 0) == "I lived")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - abatir (to knock down) — multi-word verb
|
||||||
|
|
||||||
|
@Test("abatir present: I knock down / he/she knocks down")
|
||||||
|
func abatirPresent() {
|
||||||
|
#expect(t("to knock down", "ind_presente", 0) == "I knock down")
|
||||||
|
#expect(t("to knock down", "ind_presente", 2) == "he/she knocks down")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("abatir conditional: I would knock down")
|
||||||
|
func abatirConditional() {
|
||||||
|
#expect(t("to knock down", "cond_presente", 0) == "I would knock down")
|
||||||
|
#expect(t("to knock down", "cond_presente", 2) == "he/she would knock down")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("abatir preterite: I knocked down")
|
||||||
|
func abatirPreterite() {
|
||||||
|
#expect(t("to knock down", "ind_preterito", 0) == "I knocked down")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Conditional
|
||||||
|
|
||||||
|
@Test("conditional: I would speak")
|
||||||
|
func conditional() {
|
||||||
|
#expect(t("to speak", "cond_presente", 0) == "I would speak")
|
||||||
|
#expect(t("to speak", "cond_presente", 2) == "he/she would speak")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("conditional perfect: I would have gone")
|
||||||
|
func conditionalPerfect() {
|
||||||
|
#expect(t("to go", "cond_perfecto", 0) == "I would have gone")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Subjunctive
|
||||||
|
|
||||||
|
@Test("present subjunctive: that I speak")
|
||||||
|
func presentSubjunctive() {
|
||||||
|
#expect(t("to speak", "subj_presente", 0) == "that I speak")
|
||||||
|
#expect(t("to speak", "subj_presente", 2) == "that he/she speak")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("imperfect subjunctive (ra): that I would speak")
|
||||||
|
func imperfectSubjunctive1() {
|
||||||
|
#expect(t("to speak", "subj_imperfecto_1", 0) == "that I would speak")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("imperfect subjunctive (se): that I would speak")
|
||||||
|
func imperfectSubjunctive2() {
|
||||||
|
#expect(t("to speak", "subj_imperfecto_2", 0) == "that I would speak")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("subjunctive perfect: that I have spoken")
|
||||||
|
func subjunctivePerfect() {
|
||||||
|
#expect(t("to speak", "subj_perfecto", 0) == "that I have spoken")
|
||||||
|
#expect(t("to speak", "subj_perfecto", 2) == "that he/she has spoken")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("subjunctive pluperfect: that I had gone")
|
||||||
|
func subjunctivePluperfect() {
|
||||||
|
#expect(t("to go", "subj_pluscuamperfecto_1", 0) == "that I had gone")
|
||||||
|
#expect(t("to go", "subj_pluscuamperfecto_2", 0) == "that I had gone")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("subjunctive future: that I will speak")
|
||||||
|
func subjunctiveFuture() {
|
||||||
|
#expect(t("to speak", "subj_futuro", 0) == "that I will speak")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("subjunctive future perfect: that I will have spoken")
|
||||||
|
func subjunctiveFuturePerfect() {
|
||||||
|
#expect(t("to speak", "subj_futuro_perfecto", 0) == "that I will have spoken")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Imperative
|
||||||
|
|
||||||
|
@Test("imperative affirmative")
|
||||||
|
func imperativeAffirmative() {
|
||||||
|
#expect(t("to speak", "imp_afirmativo", 1) == "speak!")
|
||||||
|
#expect(t("to speak", "imp_afirmativo", 3) == "let's speak!")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("imperative negative")
|
||||||
|
func imperativeNegative() {
|
||||||
|
#expect(t("to speak", "imp_negativo", 1) == "don't speak")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Compound indicative tenses
|
||||||
|
|
||||||
|
@Test("pluperfect: I had spoken")
|
||||||
|
func pluperfect() {
|
||||||
|
#expect(t("to speak", "ind_pluscuamperfecto", 0) == "I had spoken")
|
||||||
|
#expect(t("to go", "ind_pluscuamperfecto", 0) == "I had gone")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("future perfect: I will have spoken")
|
||||||
|
func futurePerfect() {
|
||||||
|
#expect(t("to speak", "ind_futuro_perfecto", 0) == "I will have spoken")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("preterite anterior: I had spoken (same as pluperfect in English)")
|
||||||
|
func preteriteAnterior() {
|
||||||
|
#expect(t("to speak", "ind_preterito_anterior", 0) == "I had spoken")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Edge cases
|
||||||
|
|
||||||
|
@Test("empty english returns empty string")
|
||||||
|
func emptyEnglish() {
|
||||||
|
#expect(t("", "ind_presente", 0) == "")
|
||||||
|
#expect(t("to ", "ind_presente", 0) == "")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("unknown tense falls back to pronoun + base")
|
||||||
|
func unknownTense() {
|
||||||
|
#expect(t("to speak", "some_future_tense", 0) == "I speak")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("3rd person present: study → studies")
|
||||||
|
func thirdPersonYRule() {
|
||||||
|
#expect(t("to study", "ind_presente", 2) == "he/she studies")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("3rd person present: play → plays")
|
||||||
|
func thirdPersonVowelY() {
|
||||||
|
#expect(t("to play", "ind_presente", 2) == "he/she plays")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("3rd person present: watch → watches")
|
||||||
|
func thirdPersonChRule() {
|
||||||
|
#expect(t("to watch", "ind_presente", 2) == "he/she watches")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("past regular: carry → carried")
|
||||||
|
func pastYRule() {
|
||||||
|
#expect(t("to carry", "ind_preterito", 0) == "I carried")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Helper
|
||||||
|
|
||||||
|
private func t(_ english: String, _ tenseId: String, _ personIndex: Int) -> String {
|
||||||
|
EnglishConjugator.translate(english: english, tenseId: tenseId, personIndex: personIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user