diff --git a/app/views/base/topnav.scala b/app/views/base/topnav.scala index ad008801a0..9bf690413a 100644 --- a/app/views/base/topnav.scala +++ b/app/views/base/topnav.scala @@ -43,7 +43,7 @@ object topnav { ), a(href := routes.Study.allDefault(1))(trans.studyMenu()), ctx.noKid option a(href := routes.Coach.allDefault(1))(trans.coaches()), - canSeeClasMenu option a(href := routes.Clas.index)("Classes") + canSeeClasMenu option a(href := routes.Clas.index)(trans.clas.lichessClasses()) ) ), st.section( diff --git a/app/views/clas/bits.scala b/app/views/clas/bits.scala index 39f4058389..91d5af34c7 100644 --- a/app/views/clas/bits.scala +++ b/app/views/clas/bits.scala @@ -21,7 +21,9 @@ private object bits { if (isGranted(_.Teacher)) main(cls := "page-menu")( st.nav(cls := "page-menu__menu subnav")( - a(cls := active.toOption.map(_.active("classes")), href := routes.Clas.index)("Lichess Classes"), + a(cls := active.toOption.map(_.active("classes")), href := routes.Clas.index)( + trans.clas.lichessClasses() + ), active.left.toOption.map { clas => frag( a(cls := "active", href := routes.Clas.show(clas.clas.id.value))(clas.clas.name), @@ -36,7 +38,9 @@ private object bits { } ) } | { - a(cls := active.toOption.map(_.active("newClass")), href := routes.Clas.form)("New class") + a(cls := active.toOption.map(_.active("newClass")), href := routes.Clas.form)( + trans.clas.newClass() + ) } ), div(cls := "page-menu__content box")(body) @@ -44,13 +48,8 @@ private object bits { else main(cls := "page-small box")(body) ) - def showArchived(archived: Clas.Recorded) = - div( - "Archived by ", - userIdLink(archived.by.value.some), - " ", - momentFromNowOnce(archived.at) - ) + def showArchived(archived: Clas.Recorded)(implicit ctx: Context) = + div(trans.clas.closedByXAtY(userIdLink(archived.by.value.some), momentFromNowOnce(archived.at))) val sortNumberTh = th(attr("data-sort-method") := "number") val dataSort = attr("data-sort") diff --git a/app/views/clas/clas.scala b/app/views/clas/clas.scala index d49c959271..ad6f919dce 100644 --- a/app/views/clas/clas.scala +++ b/app/views/clas/clas.scala @@ -40,27 +40,27 @@ object clas { } def teacherIndex(classes: List[Clas])(implicit ctx: Context) = - bits.layout("Lichess Classes", Right("classes"))( + bits.layout(trans.clas.lichessClasses.txt(), Right("classes"))( cls := "clas-index", div(cls := "box__top")( h1(trans.clas.lichessClasses()), a( href := routes.Clas.form, cls := "new button button-empty", - title := "New Class", + title := trans.clas.newClass.txt(), dataIcon := "O" ) ), if (classes.isEmpty) - frag(hr, p(cls := "box__pad classes__empty")("No classes yet.")) + frag(hr, p(cls := "box__pad classes__empty")(trans.clas.noClassesYet())) else renderClasses(classes) ) def studentIndex(classes: List[Clas])(implicit ctx: Context) = - bits.layout("Lichess Classes", Right("classes"))( + bits.layout(trans.clas.lichessClasses.txt(), Right("classes"))( cls := "clas-index", - div(cls := "box__top")(h1("Lichess Classes")), + div(cls := "box__top")(h1(trans.clas.lichessClasses())), renderClasses(classes) ) @@ -80,16 +80,17 @@ object clas { } ) - def teachers(clas: Clas) = + def teachers(clas: Clas)(implicit ctx: Context) = div(cls := "clas-teachers")( - "Teachers: ", - fragList(clas.teachers.toList.map(t => userIdLink(t.value.some))) + trans.clas.teachersX( + fragList(clas.teachers.toList.map(t => userIdLink(t.value.some))) + ) ) def create(form: Form[ClasData])(implicit ctx: Context) = - bits.layout("New class", Right("newClass"))( + bits.layout(trans.clas.newClass.txt(), Right("newClass"))( cls := "box-pad", - h1("New class"), + h1(trans.clas.newClass()), innerForm(form, none) ) @@ -102,9 +103,8 @@ object clas { action := routes.Clas.archive(c.id.value, true), cls := "clas-edit__archive" )( - form3.submit("Archive", icon = none)( - cls := "confirm button-red button-empty", - title := "Disband the class" + form3.submit(trans.clas.closeClass(), icon = none)( + cls := "confirm button-red button-empty" ) ) ) @@ -114,15 +114,15 @@ object clas { teacherDashboard.layout(c, students, "wall")( div(cls := "box-pad clas-wall__edit")( p( - strong("Send a message to all students."), + strong(trans.clas.sendAMessage()), br, - "A link to the class will be automatically added at the end of the message, so you don't need to include it yourself." + trans.clas.aLinkToTheClassWillBeAdded() ), postForm(cls := "form3", action := routes.Clas.notifyPost(c.id.value))( form3.globalError(form), form3.group( form("text"), - frag("Message") + frag(trans.message()) )(form3.textarea(_)(rows := 3)), form3.actions( a(href := routes.Clas.wall(c.id.value))(trans.cancel()), @@ -135,24 +135,22 @@ object clas { private def innerForm(form: Form[ClasData], clas: Option[Clas])(implicit ctx: Context) = postForm(cls := "form3", action := clas.fold(routes.Clas.create())(c => routes.Clas.update(c.id.value)))( form3.globalError(form), - form3.group(form("name"), frag("Class name"))(form3.input(_)(autofocus)), + form3.group(form("name"), trans.clas.className())(form3.input(_)(autofocus)), form3.group( form("desc"), - frag("Class description"), - help = frag("Visible by both teachers and students of the class").some + frag(trans.clas.classDescription()), + help = trans.clas.visibleByBothStudentsAndTeachers().some )(form3.textarea(_)(rows := 5)), clas match { case None => form3.hidden(form("teachers"), ctx.userId) case Some(_) => form3.group( form("teachers"), - frag("Teachers of the class"), + trans.clas.teachersOfTheClass(), help = frag( - "Add Lichess usernames to invite them as teachers. One per line.", + trans.clas.addLichessUsernames(), br, - "All teachers must be ", - a(href := routes.Clas.verifyTeacher)("vetted by Lichess"), - " before being invited." + trans.clas.theyMustFirstApply() ).some )(form3.textarea(_)(rows := 4)) }, diff --git a/app/views/clas/student.scala b/app/views/clas/student.scala index bef5431c7b..90848faf8d 100644 --- a/app/views/clas/student.scala +++ b/app/views/clas/student.scala @@ -25,10 +25,8 @@ object student { ctx.flash("password").map { password => flashMessage(cls := "student-show__password")( div( - p( - "Make sure to copy or write down the password now. You won’t be able to see it again!" - ), - pre(s"""Password: $password""") + p(trans.clas.makeSureToCopy()), + pre(trans.clas.passwordX(password)) ) ) }, @@ -36,36 +34,33 @@ object student { div(cls := "student-show__archived archived")( bits.showArchived(archived), postForm(action := routes.Clas.studentArchive(clas.id.value, s.user.username, false))( - form3.submit("Restore", icon = none)( - cls := "confirm button-empty", - title := "Get the student back into the class" - ) + form3.submit(trans.clas.inviteTheStudentBack(), icon = none)(cls := "confirm button-empty") ) ) }, s.student.notes.nonEmpty option div(cls := "student-show__notes")(richText(s.student.notes)), s.student.managed option div(cls := "student-show__managed")( - p("This student account is managed"), + p(trans.clas.thisStudentAccountIsManaged()), div(cls := "student-show__managed__actions")( postForm(action := routes.Clas.studentSetKid(clas.id.value, s.user.username, !s.user.kid))( - form3.submit(if (s.user.kid) "Disable kid mode" else "Enable kid mode", icon = none)( + form3.submit(if (s.user.kid) trans.disableKidMode() else trans.enableKidMode(), icon = none)( s.student.isArchived option disabled, cls := List("confirm button button-empty" -> true, "disabled" -> s.student.isArchived), - title := "Kid mode prevents the student from communicating with Lichess players" + title := trans.kidModeExplanation.txt() ) ), postForm(action := routes.Clas.studentResetPassword(clas.id.value, s.user.username))( - form3.submit("Reset password", icon = none)( + form3.submit(trans.clas.resetPassword(), icon = none)( s.student.isArchived option disabled, cls := List("confirm button button-empty" -> true, "disabled" -> s.student.isArchived), - title := "Generate a new password for the student" + title := trans.clas.generateANewPassword.txt() ) ), a( href := routes.Clas.studentRelease(clas.id.value, s.user.username), cls := "button button-empty", - title := "Upgrade from managed to autonomous" - )("Release") + title := trans.clas.upgradeFromManaged.txt() + )(trans.clas.release()) ) ), views.html.activity(s.user, activities) @@ -82,11 +77,10 @@ object student { ), div(cls := "student-show__top__meta")( p( - "Invited to ", - a(href := routes.Clas.show(clas.id.value))(clas.name), - " by ", - userIdLink(s.student.created.by.value.some, withOnline = false), - " ", + trans.clas.invitedToXByY( + a(href := routes.Clas.show(clas.id.value))(clas.name), + userIdLink(s.student.created.by.value.some, withOnline = false) + ), momentFromNowOnce(s.student.created.at) ), div( @@ -97,11 +91,10 @@ object student { a( href := routes.Clas.studentEdit(clas.id.value, s.user.username), cls := "button button-empty" - )("Edit"), + )(trans.edit()), a( href := routes.User.show(s.user.username), - cls := "button button-empty", - title := "View full Lichess profile" + cls := "button button-empty" )(trans.profile()) ) ) @@ -110,8 +103,8 @@ object student { private def realNameField(form: Form[_], fieldName: String = "realName")(implicit ctx: Context) = form3.group( form(fieldName), - frag("Real name"), - help = frag("Private. Will never be shown to anyone else. Helps you remember who that student is.").some + trans.clas.realName(), + help = trans.clas.privateWillNeverBeShown().some )(form3.input(_)) def form( @@ -121,45 +114,41 @@ object student { create: Form[_], created: Option[lila.clas.Student.WithPassword] = none )(implicit ctx: Context) = - bits.layout("Add student", Left(c withStudents students))( + bits.layout(trans.clas.addStudent.txt(), Left(c withStudents students))( cls := "box-pad student-add", - h1("Add student"), + h1(trans.clas.addStudent()), p( - "To ", a(href := routes.Clas.show(c.id.value))(c.name) ), created map { case Student.WithPassword(student, password) => flashMessage(cls := "student-add__created")( strong( - "Lichess profile ", - userIdLink(student.userId.some, withOnline = false), - " created for ", - student.realName, - "." - ), - p( - "Make sure to copy or write down the password now. You won’t be able to see it again!" - ), - pre(s"""Student: ${student.realName} -Username: ${usernameOrId(student.userId)} -Password: ${password.value}""") + trans.clas.lichessProfileXCreatedForY( + userIdLink(student.userId.some, withOnline = false), + student.realName + ), + p(trans.clas.makeSureToCopy()), + pre( + trans.clas.studentCredentials(student.realName, usernameOrId(student.userId), password.value) + ) + ) ) }, standardFlash(), div(cls := "student-add__choice")( div(cls := "info")( - h2("Invite a Lichess account"), - p("If the student already has a Lichess account, you can invite them to the class."), - p("They will receive a message on Lichess with a link to join the class."), + h2(trans.clas.inviteALichessAccount()), + p(trans.clas.inviteDesc1()), + p(trans.clas.inviteDesc2()), p( - strong("Important: only invite students you know, and who actively want to join the class."), + strong(trans.clas.inviteDesc3()), br, - "Never send unsolicited invites to arbitrary players." + trans.clas.inviteDesc4() ) ), postForm(cls := "form3", action := routes.Clas.studentInvite(c.id.value))( - form3.group(invite("username"), frag("Lichess username"))( + form3.group(invite("username"), trans.clas.lichessUsername())( form3.input(_, klass = "user-autocomplete")(created.isEmpty option autofocus)(dataTag := "span") ), realNameField(invite), @@ -169,24 +158,23 @@ Password: ${password.value}""") div(cls := "student-add__or")("~ or ~"), div(cls := "student-add__choice")( div(cls := "info")( - h2("Create a new Lichess account"), - p("If the student doesn't have a Lichess account yet, you can create one for them here."), + h2(trans.clas.createANewLichessAccount()), + p(trans.clas.createDesc1()), p( - "No email address is required. A password will be generated, ", - "and you will have to transmit it to the student, so they can log in." + trans.clas.createDesc2() ), p( - strong("Important: a student must not have multiple accounts."), + strong(trans.clas.createDesc3()), br, - "If they already have one, use the invite form instead." + trans.clas.createDesc4() ) ), postForm(cls := "form3", action := routes.Clas.studentCreate(c.id.value))( form3.group( create("create-username"), - frag("Lichess username"), + trans.clas.lichessUsername(), help = a(cls := "name-regen", href := s"${routes.Clas.studentForm(c.id.value)}?gen=1")( - "Generate a new username" + trans.clas.generateANewUsername() ).some )( form3.input(_)(created.isDefined option autofocus) @@ -206,7 +194,7 @@ Password: ${password.value}""") postForm(cls := "form3", action := routes.Clas.studentUpdate(clas.id.value, s.user.username))( form3.globalError(form), realNameField(form), - form3.group(form("notes"), raw("Notes"), help = frag("Only visible to the class teachers").some)( + form3.group(form("notes"), trans.notes(), help = trans.clas.onlyVisibleToTeachers().some)( form3.textarea(_)(autofocus, rows := 15) ), form3.actions( @@ -220,9 +208,8 @@ Password: ${password.value}""") action := routes.Clas.studentArchive(clas.id.value, s.user.username, true), cls := "student-show__archive" )( - form3.submit("Archive", icon = none)( - cls := "confirm button-red button-empty", - title := "Remove the student from the class" + form3.submit(trans.clas.removeStudent(), icon = none)( + cls := "confirm button-red button-empty" ) ) ) @@ -236,20 +223,18 @@ Password: ${password.value}""") cls := "student-show student-edit", top(clas, s), div(cls := "box__pad")( - h2("Release the account so the student can manage it in autonomy."), + h2(trans.clas.releaseTheAccount()), p( - "A released account cannot be made managed again. The student will be able to toggle kid mode and reset paswword themselves.", + trans.clas.releaseDesc1(), br, - "The student will remain in the class after their account is released." + trans.clas.releaseDesc2() ), postForm(cls := "form3", action := routes.Clas.studentReleasePost(clas.id.value, s.user.username))( form3.globalError(form), form3.group( form("email"), trans.email(), - help = frag( - "Real, unique email address of the student. We will send a confirmation email to it, with a link to release the account." - ).some + help = trans.clas.realUniqueEmail().some )(form3.input(_, typ = "email")(autofocus, required)), form3.actions( a(href := routes.Clas.studentShow(clas.id.value, s.user.username))(trans.cancel()), diff --git a/app/views/clas/studentDashboard.scala b/app/views/clas/studentDashboard.scala index eb6c3240c6..bbc6afc484 100644 --- a/app/views/clas/studentDashboard.scala +++ b/app/views/clas/studentDashboard.scala @@ -31,7 +31,7 @@ object studentDashboard { table(cls := "slist slist-pad teachers")( thead( tr( - th("Teachers"), + th(trans.clas.nbTeachers(teachers.size)), th, th ) @@ -68,10 +68,10 @@ object studentDashboard { table(cls := "slist slist-pad sortable")( thead( tr( - th(attr("data-sort-default") := "1")("Students"), - sortNumberTh("Rating"), - sortNumberTh("Games"), - sortNumberTh("Puzzles"), + th(attr("data-sort-default") := "1")(trans.clas.nbStudents(students.size)), + sortNumberTh(trans.rating()), + sortNumberTh(trans.games()), + sortNumberTh(trans.puzzles()), th ) ), diff --git a/app/views/clas/teacherDashboard.scala b/app/views/clas/teacherDashboard.scala index 472805d995..76044157c6 100644 --- a/app/views/clas/teacherDashboard.scala +++ b/app/views/clas/teacherDashboard.scala @@ -27,11 +27,11 @@ object teacherDashboard { a( cls := active.active("progress"), href := routes.Clas.progress(c.id.value, PerfType.Blitz.key, 7) - )( - "Progress" - ), - a(cls := active.active("edit"), href := routes.Clas.edit(c.id.value))("Edit"), - a(cls := active.active("archived"), href := routes.Clas.archived(c.id.value))("Archived") + )(trans.clas.progress()), + a(cls := active.active("edit"), href := routes.Clas.edit(c.id.value))(trans.edit()), + a(cls := active.active("archived"), href := routes.Clas.archived(c.id.value))( + trans.clas.removedStudents() + ) ) ), standardFlash(), @@ -39,10 +39,7 @@ object teacherDashboard { div(cls := "clas-show__archived archived")( bits.showArchived(archived), postForm(action := routes.Clas.archive(c.id.value, false))( - form3.submit("Restore", icon = none)( - cls := "confirm button-empty", - title := "Revive the class" - ) + form3.submit(trans.clas.reopen(), icon = none)(cls := "confirm button-empty") ) ) }, @@ -62,11 +59,11 @@ object teacherDashboard { href := routes.Clas.studentForm(c.id.value), cls := "button button-clas text", dataIcon := "O" - )("Add student") + )(trans.clas.addStudent()) ) ), if (students.isEmpty) - p(cls := "box__pad students__empty")("No students in the class, yet.") + p(cls := "box__pad students__empty")(trans.clas.noStudents()) else studentList(c, students) ) @@ -78,7 +75,7 @@ object teacherDashboard { layout(c, students.filter(_.student.isActive), "archived") { val archived = students.filter(_.student.isArchived) if (archived.isEmpty) - p(cls := "box__pad students__empty")("No archived students.") + p(cls := "box__pad students__empty")(trans.clas.noStudents()) else studentList(c, archived) } @@ -91,7 +88,7 @@ object teacherDashboard { layout(c, students, "progress")( div(cls := "progress")( div(cls := "progress-perf")( - label("Variant"), + label(trans.variant()), div(cls := "progress-choices")( List( PerfType.Bullet, @@ -109,7 +106,7 @@ object teacherDashboard { ) ), div(cls := "progress-days")( - label("Over days"), + label(trans.clas.overDays()), div(cls := "progress-choices")( List(1, 2, 3, 7, 10, 14, 21, 30, 60, 90).map { days => a( @@ -125,30 +122,32 @@ object teacherDashboard { thead( tr( th(attr("data-sort-default") := "1")( - s"${progress.perfType.name} over last ${progress.days} days" - ), - sortNumberTh("Rating"), - sortNumberTh("Progress"), - sortNumberTh(if (progress.isPuzzle) "Puzzles" else "Games"), - if (progress.isPuzzle) sortNumberTh("Winrate") - else sortNumberTh("Time playing") + trans.clas.variantXOverLastY(progress.perfType.name, trans.nbDays.txt(progress.days)), + sortNumberTh(trans.rating()), + sortNumberTh(trans.clas.progress()), + sortNumberTh(if (progress.isPuzzle) trans.puzzles() else trans.games()), + if (progress.isPuzzle) sortNumberTh(trans.clas.winrate()) + else sortNumberTh(trans.clas.timePlaying()) + ) + ), + tbody( + students.sortBy(_.user.username).map { + case s @ Student.WithUser(_, user) => + val prog = progress(user) + tr( + studentTd(c, s), + td(dataSort := user.perfs(progress.perfType).intRating, cls := "rating")( + user.perfs(progress.perfType).showRatingProvisional + ), + td(dataSort := prog.ratingProgress)( + ratingProgress(prog.ratingProgress) | trans.clas.na.txt() + ), + td(prog.nb), + if (progress.isPuzzle) td(dataSort := prog.winRate)(prog.winRate, "%") + else td(dataSort := prog.millis)(showPeriod(prog.period)) + ) + } ) - ), - tbody( - students.sortBy(_.user.username).map { - case s @ Student.WithUser(_, user) => - val prog = progress(user) - tr( - studentTd(c, s), - td(dataSort := user.perfs(progress.perfType).intRating, cls := "rating")( - user.perfs(progress.perfType).showRatingProvisional - ), - td(dataSort := prog.ratingProgress)(ratingProgress(prog.ratingProgress) | "N/A"), - td(prog.nb), - if (progress.isPuzzle) td(dataSort := prog.winRate)(prog.winRate, "%") - else td(dataSort := prog.millis)(showPeriod(prog.period)) - ) - } ) ) ) @@ -159,12 +158,12 @@ object teacherDashboard { table(cls := "slist slist-pad sortable")( thead( tr( - th(attr("data-sort-default") := "1")("Student"), - sortNumberTh("Rating"), - sortNumberTh("Games"), - sortNumberTh("Puzzles"), - sortNumberTh("Active"), - th(iconTag("5")(title := "Managed")) + th(attr("data-sort-default") := "1")(trans.clas.nbStudents(students.size)), + sortNumberTh(trans.rating()), + sortNumberTh(trans.games()), + sortNumberTh(trans.puzzles()), + sortNumberTh(trans.clas.lastActiveDate()), + th(iconTag("5")(title := trans.clas.managed.txt())) ) ), tbody( @@ -178,7 +177,7 @@ object teacherDashboard { td(user.count.game.localize), td(user.perfs.puzzle.nb), td(dataSort := user.seenAt.map(_.getMillis.toString))(user.seenAt.map(momentFromNowOnce)), - td(student.managed option iconTag("5")(title := "Managed")) + td(student.managed option iconTag("5")(title := trans.clas.managed.txt())) ) } ) diff --git a/app/views/clas/wall.scala b/app/views/clas/wall.scala index 12be1f6f23..3764ae22e6 100644 --- a/app/views/clas/wall.scala +++ b/app/views/clas/wall.scala @@ -18,14 +18,14 @@ object wall { teacherDashboard.layout(c, students.filter(_.student.isActive), "wall")( div(cls := "clas-wall__actions")( a(dataIcon := "m", href := routes.Clas.wallEdit(c.id.value), cls := "button button-clas text")( - "Edit news" + trans.clas.editNews() ), a(dataIcon := "e", href := routes.Clas.notifyStudents(c.id.value), cls := "button button-clas text")( - "Notify all students" + trans.clas.notifyAllStudents() ) ), if (c.wall.isEmpty) - div(cls := "box__pad clas-wall clas-wall--empty")("Nothing here, yet.") + div(cls := "box__pad clas-wall clas-wall--empty")(trans.clas.nothingHere()) else div(cls := "box__pad clas-wall")(html) ) @@ -38,15 +38,16 @@ object wall { teacherDashboard.layout(c, students, "wall")( div(cls := "box-pad clas-wall__edit")( p( - strong("All class news in a single field."), + strong(trans.clas.newsEdit1()), ul( - li("Add the recent news at the top. Don't delete previous news."), - li("Separate news with --- it will display a horizontal line."), + li(trans.clas.newsEdit2()), + li(trans.clas.newsEdit3()), li( - a(href := "https://guides.github.com/features/mastering-markdown/", target := "_blank")( - "Markdown" - ), - " is available for more advanced syntax." + trans.clas.markdownAvailable( + a(href := "https://guides.github.com/features/mastering-markdown/", target := "_blank")( + "Markdown" + ) + ) ) ) ), @@ -54,7 +55,7 @@ object wall { form3.globalError(form), form3.group( form("wall"), - frag("Class news") + trans.clas.news() )(form3.textarea(_)(rows := 20)), form3.actions( a(href := routes.Clas.wall(c.id.value))(trans.cancel()), diff --git a/modules/i18n/src/main/I18nKeys.scala b/modules/i18n/src/main/I18nKeys.scala index 0fcddd5278..b96497ccda 100644 --- a/modules/i18n/src/main/I18nKeys.scala +++ b/modules/i18n/src/main/I18nKeys.scala @@ -756,6 +756,7 @@ val `agreementNice` = new Translated("agreementNice", Site) val `agreementAccount` = new Translated("agreementAccount", Site) val `agreementPolicy` = new Translated("agreementPolicy", Site) val `searchOrStartNewDiscussion` = new Translated("searchOrStartNewDiscussion", Site) +val `edit` = new Translated("edit", Site) val `opponentLeftCounter` = new Translated("opponentLeftCounter", Site) val `mateInXHalfMoves` = new Translated("mateInXHalfMoves", Site) val `nextCaptureOrPawnMoveInXHalfMoves` = new Translated("nextCaptureOrPawnMoveInXHalfMoves", Site) @@ -1167,6 +1168,73 @@ val `trackStudentProgress` = new Translated("trackStudentProgress", Clas) val `messageAllStudents` = new Translated("messageAllStudents", Clas) val `freeForAllForever` = new Translated("freeForAllForever", Clas) val `applyToBeLichessTeacher` = new Translated("applyToBeLichessTeacher", Clas) +val `noClassesYet` = new Translated("noClassesYet", Clas) +val `teachersX` = new Translated("teachersX", Clas) +val `newClass` = new Translated("newClass", Clas) +val `closeClass` = new Translated("closeClass", Clas) +val `closedByXAtY` = new Translated("closedByXAtY", Clas) +val `reopen` = new Translated("reopen", Clas) +val `removeStudent` = new Translated("removeStudent", Clas) +val `removedStudents` = new Translated("removedStudents", Clas) +val `inviteTheStudentBack` = new Translated("inviteTheStudentBack", Clas) +val `sendAMessage` = new Translated("sendAMessage", Clas) +val `aLinkToTheClassWillBeAdded` = new Translated("aLinkToTheClassWillBeAdded", Clas) +val `className` = new Translated("className", Clas) +val `classDescription` = new Translated("classDescription", Clas) +val `visibleByBothStudentsAndTeachers` = new Translated("visibleByBothStudentsAndTeachers", Clas) +val `teachersOfTheClass` = new Translated("teachersOfTheClass", Clas) +val `addLichessUsernames` = new Translated("addLichessUsernames", Clas) +val `theyMustFirstApply` = new Translated("theyMustFirstApply", Clas) +val `resetPassword` = new Translated("resetPassword", Clas) +val `makeSureToCopy` = new Translated("makeSureToCopy", Clas) +val `passwordX` = new Translated("passwordX", Clas) +val `generateANewPassword` = new Translated("generateANewPassword", Clas) +val `invitedToXByY` = new Translated("invitedToXByY", Clas) +val `realName` = new Translated("realName", Clas) +val `privateWillNeverBeShown` = new Translated("privateWillNeverBeShown", Clas) +val `addStudent` = new Translated("addStudent", Clas) +val `lichessProfileXCreatedForY` = new Translated("lichessProfileXCreatedForY", Clas) +val `studentCredentials` = new Translated("studentCredentials", Clas) +val `inviteALichessAccount` = new Translated("inviteALichessAccount", Clas) +val `inviteDesc1` = new Translated("inviteDesc1", Clas) +val `inviteDesc2` = new Translated("inviteDesc2", Clas) +val `inviteDesc3` = new Translated("inviteDesc3", Clas) +val `inviteDesc4` = new Translated("inviteDesc4", Clas) +val `createANewLichessAccount` = new Translated("createANewLichessAccount", Clas) +val `createDesc1` = new Translated("createDesc1", Clas) +val `createDesc2` = new Translated("createDesc2", Clas) +val `createDesc3` = new Translated("createDesc3", Clas) +val `createDesc4` = new Translated("createDesc4", Clas) +val `lichessUsername` = new Translated("lichessUsername", Clas) +val `generateANewUsername` = new Translated("generateANewUsername", Clas) +val `onlyVisibleToTeachers` = new Translated("onlyVisibleToTeachers", Clas) +val `lastActiveDate` = new Translated("lastActiveDate", Clas) +val `managed` = new Translated("managed", Clas) +val `thisStudentAccountIsManaged` = new Translated("thisStudentAccountIsManaged", Clas) +val `upgradeFromManaged` = new Translated("upgradeFromManaged", Clas) +val `release` = new Translated("release", Clas) +val `releaseTheAccount` = new Translated("releaseTheAccount", Clas) +val `releaseDesc1` = new Translated("releaseDesc1", Clas) +val `releaseDesc2` = new Translated("releaseDesc2", Clas) +val `realUniqueEmail` = new Translated("realUniqueEmail", Clas) +val `teachers` = new Translated("teachers", Clas) +val `progress` = new Translated("progress", Clas) +val `noStudents` = new Translated("noStudents", Clas) +val `overDays` = new Translated("overDays", Clas) +val `timePlaying` = new Translated("timePlaying", Clas) +val `variantXOverLastY` = new Translated("variantXOverLastY", Clas) +val `winrate` = new Translated("winrate", Clas) +val `na` = new Translated("na", Clas) +val `news` = new Translated("news", Clas) +val `editNews` = new Translated("editNews", Clas) +val `notifyAllStudents` = new Translated("notifyAllStudents", Clas) +val `nothingHere` = new Translated("nothingHere", Clas) +val `newsEdit1` = new Translated("newsEdit1", Clas) +val `newsEdit2` = new Translated("newsEdit2", Clas) +val `newsEdit3` = new Translated("newsEdit3", Clas) +val `markdownAvailable` = new Translated("markdownAvailable", Clas) +val `nbTeachers` = new Translated("nbTeachers", Clas) +val `nbStudents` = new Translated("nbStudents", Clas) } } diff --git a/translation/source/class.xml b/translation/source/class.xml index b6ab437541..88c45497a0 100644 --- a/translation/source/class.xml +++ b/translation/source/class.xml @@ -8,4 +8,81 @@ Message all students about new class material 100% free for all, forever, with no ads or trackers Apply to be a Lichess Teacher + No classes yet. + Teachers: %s + New class + Close class + Closed by %1$s %2$s + Reopen + Remove student + Removed + Invite the student back + Send a message to all students. + A link to the class will be automatically added at the end of the message, so you don't need to include it yourself. + Class name + Class description + Visible by both teachers and students of the class + Teachers of the class + Add Lichess usernames to invite them as teachers. One per line. + They must first apply to be Lichess Teachers. + Reset password + Make sure to copy or write down the password now. You won’t be able to see it again! + Password: %s + Generate a new password for the student + Invited to %1$s by %2$s + Real name + Private. Will never be shown outside the class. Helps remember who the student is. + Add student + Lichess profile %1$s created for %2$s. + +Student: %1$s +Username: %2$s +Password: %2$s + + Invite a Lichess account + If the student already has a Lichess account, you can invite them to the class. + They will receive a message on Lichess with a link to join the class. + Important: only invite students you know, and who actively want to join the class. + Never send unsolicited invites to arbitrary players. + Create a new Lichess account + If the student doesn't have a Lichess account yet, you can create one for them here. + No email address is required. A password will be generated, and you will have to transmit it to the student, so they can log in. + Important: a student must not have multiple accounts. + If they already have one, use the invite form instead. + Lichess username + Generate a new username + Only visible to the class teachers + Active + Managed + This student account is managed + Upgrade from managed to autonomous + Release + Release the account so the student can manage it in autonomy. + A released account cannot be made managed again. The student will be able to toggle kid mode and reset paswword themselves. + The student will remain in the class after their account is released. + Real, unique email address of the student. We will send a confirmation email to it, with a link to release the account. + Teachers + + Teacher + %s teachers + + + Student + %s students + + Progress + No students in the class, yet. + "Over days" + Time playing + %1$s over last %2$s + Winrate + N/A + Class news + Edit news + Notify all students + Nothing here, yet. + All class news in a single field. + Add the recent news at the top. Don't delete previous news. + Separate news with --- it will display a horizontal line. + %s is available for more advanced syntax. diff --git a/translation/source/site.xml b/translation/source/site.xml index 01be9fc1b3..767e2f6a5b 100644 --- a/translation/source/site.xml +++ b/translation/source/site.xml @@ -901,4 +901,5 @@ computer analysis, game chat and shareable URL. I agree that I will not create multiple accounts. I agree that I will follow all Lichess policies. Search or start new discussion + Edit