translate /coach public UI

pull/6012/head
Thibault Duplessis 2020-02-09 12:27:56 -06:00
parent 67ee55bd32
commit 7a791660c6
10 changed files with 115 additions and 51 deletions

View File

@ -10,32 +10,27 @@ import controllers.routes
object index {
import trans.coach._
def apply(pager: Paginator[lila.coach.Coach.WithUser], order: lila.coach.CoachPager.Order)(
implicit ctx: Context
) =
views.html.base.layout(
title = "Lichess coaches",
title = lichessCoaches.txt(),
moreCss = cssTag("coach"),
moreJs = infiniteScrollTag
) {
main(cls := "coach-list coach-full-page")(
st.aside(cls := "coach-list__side coach-side")(
p(
"Are you a great chess coach?",
areYouCoach(a(href := "https://lichess.org/help/master")(nmOrFideTitle())),
br,
"Do you have a ",
a(href := "https://lichess.org/help/master")("FIDE title"),
"?",
br,
"Send us an email at ",
contactEmailLink,
br,
"and we will review your application."
sendApplication(contactEmailLink)
)
),
div(cls := "coach-list__main coach-main box")(
div(cls := "box__top")(
h1("Top chess coaches"),
h1(lichessCoaches()),
div(cls := "box__top__actions")(
views.html.base.bits.mselect(
"coach-sort",

View File

@ -9,9 +9,11 @@ import controllers.routes
object review {
import trans.coach._
def list(reviews: lila.coach.CoachReview.Reviews)(implicit ctx: Context) =
reviews.list.nonEmpty option div(cls := "coach-show__reviews")(
h2(pluralize("Player review", reviews.list.size)),
h2(studentReviews(reviews.list.size)),
reviews.list.map { r =>
div(cls := "coach-review")(
div(cls := "top")(
@ -34,11 +36,11 @@ object review {
div(cls := "coach-review-form")(
if (mine.exists(_.pendingApproval))
div(cls := "approval")(
p("Thank you for the review!"),
p(c.user.realNameOrUsername, " will approve it very soon, or a moderator will have a look at it.")
p(thankYouForReview()),
p(xWillApproveIt(c.user.realNameOrUsername))
)
else if (ctx.isAuth) a(cls := "button button-empty toggle")("Write a review")
else a(href := s"${routes.Auth.login}?referrer=${ctx.req.path}", cls := "button")("Review this coach"),
else a(href := s"${routes.Auth.login}?referrer=${ctx.req.path}", cls := "button")(reviewCoach()),
postForm(action := routes.Coach.review(c.user.username))(
barRating(selected = mine.map(_.score), enabled = true),
textarea(
@ -46,7 +48,7 @@ object review {
required,
minlength := 3,
maxlength := 2000,
placeholder := s"Describe your coaching experience with ${c.user.realNameOrUsername}"
placeholder := describeExperienceWith.txt(c.user.realNameOrUsername)
)(mine.map(_.text)),
submitButton(cls := "button")(trans.apply())
)

View File

@ -10,7 +10,9 @@ import controllers.routes
object show {
private def section(title: String, text: Option[lila.coach.CoachProfile.RichText]) = text.map { t =>
import trans.coach._
private def section(title: Frag, text: Option[lila.coach.CoachProfile.RichText]) = text.map { t =>
st.section(
h2(title),
div(cls := "content")(richText(t.value))
@ -25,7 +27,7 @@ object show {
)(implicit ctx: Context) = {
val profile = c.coach.profile
val coachName = s"${c.user.title.??(t => s"$t ")}${c.user.realNameOrUsername}"
val title = s"$coachName coaches chess students"
val title = xCoachesStudents.txt(coachName)
views.html.base.layout(
title = title,
moreJs = frag(
@ -52,9 +54,7 @@ $('.coach-review-form form').show();
main(cls := "coach-show coach-full-page")(
st.aside(cls := "coach-show__side coach-side")(
a(cls := "button button-empty", href := routes.User.show(c.user.username))(
"View ",
c.user.username,
" lichess profile"
viewXProfile(c.user.username)
),
if (ctx.me.exists(c.coach.is))
frag(
@ -67,24 +67,22 @@ $('.coach-review-form form').show();
cls := "text button button-empty",
dataIcon := "c",
href := s"${routes.Msg.convo(c.user.username)}"
)(
"Send a private message"
),
)(sendPM()),
ctx.me.exists(_.id != c.user.id) option review.form(c, myReview),
review.list(coachReviews)
),
div(cls := "coach-show__main coach-main box")(
div(cls := "coach-widget")(widget(c, link = false)),
div(cls := "coach-show__sections")(
section("About me", profile.description),
section("Playing experience", profile.playingExperience),
section("Teaching experience", profile.teachingExperience),
section("Other experiences", profile.otherExperience),
section("Best skills", profile.skills),
section("Teaching methodology", profile.methodology)
section(aboutMe(), profile.description),
section(playingExperience(), profile.playingExperience),
section(teachingExperience(), profile.teachingExperience),
section(otherExperiences(), profile.otherExperience),
section(bestSkills(), profile.skills),
section(teachingMethod(), profile.methodology)
),
studies.nonEmpty option st.section(cls := "coach-show__studies")(
h2("Public studies"),
h2(publicStudies()),
div(cls := "studies")(
studies.map { s =>
st.article(cls := "study")(study.bits.widget(s, h3))
@ -93,13 +91,9 @@ $('.coach-review-form form').show();
),
profile.youtubeUrls.nonEmpty option st.section(cls := "coach-show__youtube")(
h2(
"Youtube videos",
profile.youtubeChannel.map { url =>
frag(
" from my ",
a(href := url, target := "_blank", rel := "nofollow")("channel")
)
}
a(href := url, target := "_blank", rel := "nofollow")(youtubeVideos())
} getOrElse youtubeVideos()
),
div(cls := "list")(
profile.youtubeUrls.map { url =>

View File

@ -9,6 +9,8 @@ import controllers.routes
object widget {
import trans.coach._
def titleName(c: lila.coach.Coach.WithUser) = frag(
c.user.title.map { t =>
s"$t "
@ -24,7 +26,7 @@ object widget {
height := size,
cls := "picture",
src := dbImageUrl(path.value),
alt := s"${c.user.titleUsername} lichess coach"
alt := s"${c.user.titleUsername} Lichess coach picture"
)
}
.getOrElse {
@ -32,7 +34,8 @@ object widget {
width := size,
height := size,
cls := "default picture",
src := staticUrl("images/placeholder.png")
src := staticUrl("images/placeholder.png"),
alt := "Default Lichess coach picture"
)
}
@ -49,7 +52,7 @@ object widget {
table(
tbody(
tr(
th("Location"),
th(location()),
td(
profile.nonEmptyLocation.map { l =>
span(cls := "location")(l)
@ -67,12 +70,12 @@ object widget {
),
c.coach.profile.languages.map { l =>
tr(cls := "languages")(
th("Languages"),
th(languages()),
td(l)
)
},
tr(cls := "rating")(
th("Rating"),
th(rating()),
td(
profile.fideRating.map { r =>
frag("FIDE: ", r)
@ -86,15 +89,15 @@ object widget {
),
c.coach.profile.hourlyRate.map { r =>
tr(cls := "rate")(
th("Hourly rate"),
th(hourlyRate()),
td(r)
)
},
tr(cls := "available")(
th("Availability"),
th(availability()),
td(
if (c.coach.available.value) span(cls := "text", dataIcon := "E")("Accepting students")
else span(cls := "text", dataIcon := "L")("Not accepting students at the moment")
if (c.coach.available.value) span(cls := "text", dataIcon := "E")(accepting())
else span(cls := "text", dataIcon := "L")(notAccepting())
)
),
c.user.seenAt.map { seen =>

View File

@ -1,5 +1,7 @@
package views.html.user.show
import play.api.i18n.Lang
import lila.app.templating.Environment._
import lila.app.ui.ScalatagsTemplate._
import lila.user.{ Trophy, TrophyKind }
@ -9,7 +11,7 @@ import controllers.routes
object otherTrophies {
def apply(u: User, info: lila.app.mashup.UserInfo) = frag(
def apply(u: User, info: lila.app.mashup.UserInfo)(implicit lang: Lang) = frag(
info.trophies.filter(_.kind.klass.has("fire-trophy")).some.filter(_.nonEmpty) map { trophies =>
div(cls := "stacked")(
trophies.sorted.map { trophy =>
@ -85,7 +87,7 @@ object otherTrophies {
a(
href := routes.Coach.show(u.username),
cls := "trophy award icon3d coach",
ariaTitle("Lichess Coach")
ariaTitle(trans.coach.lichessCoach.txt())
)(":"),
info.isStreamer option
a(

View File

@ -2,7 +2,7 @@ const fs = require('fs-extra');
const parseString = require('xml2js').parseString;
const baseDir = 'translation/source';
const dbs = ['site', 'arena', 'emails', 'learn', 'activity', 'coordinates', 'study', 'clas', 'contact', 'patron'];
const dbs = ['site', 'arena', 'emails', 'learn', 'activity', 'coordinates', 'study', 'clas', 'contact', 'patron', 'coach'];
function ucfirst(s) {
return s.charAt(0).toUpperCase() + s.slice(1);

View File

@ -76,7 +76,7 @@ lazy val i18n = module("i18n",
MessageCompiler(
sourceDir = new File("translation/source"),
destDir = new File("translation/dest"),
dbs = List("site", "arena", "emails", "learn", "activity", "coordinates", "study", "class", "contact", "patron"),
dbs = List("site", "arena", "emails", "learn", "activity", "coordinates", "study", "class", "contact", "patron", "coach"),
compileTo = (sourceManaged in Compile).value / "messages"
)
}.taskValue,

View File

@ -15,6 +15,7 @@ object I18nDb {
case object Clas extends Ref
case object Contact extends Ref
case object Patron extends Ref
case object Coach extends Ref
val site: Messages = lila.i18n.db.site.Registry.load
val arena: Messages = lila.i18n.db.arena.Registry.load
@ -26,6 +27,7 @@ object I18nDb {
val clas: Messages = lila.i18n.db.clas.Registry.load
val contact: Messages = lila.i18n.db.contact.Registry.load
val patron: Messages = lila.i18n.db.patron.Registry.load
val coach: Messages = lila.i18n.db.coach.Registry.load
def apply(ref: Ref): Messages = ref match {
case Site => site
@ -38,6 +40,7 @@ object I18nDb {
case Clas => clas
case Contact => contact
case Patron => patron
case Coach => coach
}
val langs: Set[Lang] = site.keys.toSet

View File

@ -1,7 +1,7 @@
// Generated with bin/trans-dump.js
package lila.i18n
import I18nDb.{ Activity, Arena, Clas, Contact, Coordinates, Emails, Learn, Patron, Site, Study }
import I18nDb.{ Activity, Arena, Clas, Coach, Contact, Coordinates, Emails, Learn, Patron, Site, Study }
// format: OFF
object I18nKeys {
@ -1387,4 +1387,35 @@ val `downgradeNextMonth` = new Translated("downgradeNextMonth", Patron)
val `patronForMonths` = new Translated("patronForMonths", Patron)
}
object coach {
val `lichessCoaches` = new Translated("lichessCoaches", Coach)
val `lichessCoach` = new Translated("lichessCoach", Coach)
val `areYouCoach` = new Translated("areYouCoach", Coach)
val `nmOrFideTitle` = new Translated("nmOrFideTitle", Coach)
val `sendApplication` = new Translated("sendApplication", Coach)
val `location` = new Translated("location", Coach)
val `languages` = new Translated("languages", Coach)
val `rating` = new Translated("rating", Coach)
val `hourlyRate` = new Translated("hourlyRate", Coach)
val `availability` = new Translated("availability", Coach)
val `accepting` = new Translated("accepting", Coach)
val `notAccepting` = new Translated("notAccepting", Coach)
val `xCoachesStudents` = new Translated("xCoachesStudents", Coach)
val `viewXProfile` = new Translated("viewXProfile", Coach)
val `sendPM` = new Translated("sendPM", Coach)
val `aboutMe` = new Translated("aboutMe", Coach)
val `playingExperience` = new Translated("playingExperience", Coach)
val `teachingExperience` = new Translated("teachingExperience", Coach)
val `otherExperiences` = new Translated("otherExperiences", Coach)
val `bestSkills` = new Translated("bestSkills", Coach)
val `teachingMethod` = new Translated("teachingMethod", Coach)
val `publicStudies` = new Translated("publicStudies", Coach)
val `youtubeVideos` = new Translated("youtubeVideos", Coach)
val `thankYouForReview` = new Translated("thankYouForReview", Coach)
val `xWillApproveIt` = new Translated("xWillApproveIt", Coach)
val `reviewCoach` = new Translated("reviewCoach", Coach)
val `describeExperienceWith` = new Translated("describeExperienceWith", Coach)
val `studentReviews` = new Translated("studentReviews", Coach)
}
}

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<string name="lichessCoaches">Lichess coaches</string>
<string name="lichessCoach">Lichess coach</string>
<string name="areYouCoach">Are you a great chess coach with a %s?</string>
<string name="nmOrFideTitle">NM or FIDE title</string>
<string name="sendApplication">Send us an email at %s and we will review your application.</string>
<string name="location">Location</string>
<string name="languages">Languages</string>
<string name="rating">Rating</string>
<string name="hourlyRate">Hourly rate</string>
<string name="availability">Availability</string>
<string name="accepting">Accepting students</string>
<string name="notAccepting">Not accepting students at the moment</string>
<string name="xCoachesStudents">%s coaches chess students</string>
<string name="viewXProfile">View %s Lichess profile</string>
<string name="sendPM">Send a private message</string>
<string name="aboutMe">About me</string>
<string name="playingExperience">Playing experience</string>
<string name="teachingExperience">Teaching experience</string>
<string name="otherExperiences">Other experiences</string>
<string name="bestSkills">Best skills</string>
<string name="teachingMethod">Teaching methodology</string>
<string name="publicStudies">Public studies</string>
<string name="youtubeVideos">Youtube videos</string>
<plurals name="studentReviews">
<item quantity="one">One student review</item>
<item quantity="other">%s student reviews</item>
</plurals>
<string name="thankYouForReview">Thank you for the review!</string>
<string name="xWillApproveIt">%s will approve it very soon, or a moderator will have a look at it.</string>
<string name="reviewCoach">Review this coach</string>
<string name="describeExperienceWith">Describe your coaching experience with %s</string>
</resources>