Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
9e4a5b1
i17097: Initial translation for practice section
shprotru Aug 11, 2025
2f0ad98
Update modules.scala
shprotru Aug 11, 2025
c7dc2d4
i17097: Implemented more translatable symbols
shprotru Aug 11, 2025
366d663
i17097: Applying translation
shprotru Aug 11, 2025
ff3ec96
i17097: Added section headers translation
shprotru Aug 12, 2025
b17b110
i17097: fix format issues
shprotru Aug 12, 2025
5e4b11a
i17097: translation for section names and section descrions
shprotru Aug 13, 2025
c62d6d0
i17097: final fixups
shprotru Aug 13, 2025
9b9a47c
Merge branch 'master' into i17097_practice
ornicar Aug 15, 2025
fe45fb4
scala tweaks, use types wherever we can
ornicar Aug 15, 2025
4127365
quit pretending that practice sections are dynamic
ornicar Aug 15, 2025
23006a5
Merge branch 'master' into i17097_practice
shprotru Aug 15, 2025
34ea25e
Merge branch 'master' into i17097_practice
ornicar Aug 15, 2025
70d36ea
Merge branch 'master' into i17097_practice
ornicar Aug 16, 2025
a2380df
Update ru-RU.xml
shprotru Aug 18, 2025
ba9cb73
Merge branch 'master' into i17097_practice
ornicar Sep 19, 2025
a697cab
start integrating practice translation keys into the practice structure
ornicar Sep 19, 2025
3bf82b1
move more practice translation keys to the practice structure - WIP
ornicar Sep 19, 2025
354cfcf
Merge branch 'master' into i17097_practice
ornicar Sep 19, 2025
06d04f1
complete merging practice translation keys into the structure
ornicar Sep 19, 2025
027d903
remove a couple of superfluous translation keys
ornicar Sep 19, 2025
47dceab
remove unnecessary text and translation
ornicar Sep 19, 2025
30b3f86
remove translation/dest/practice/*
ornicar Sep 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion app/controllers/Practice.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ final class Practice(

private val api = env.practice.api

def index = OpenOrScoped(_.Web.Mobile):
def indexLang = LangPage(routes.Practice.index)(serveIndex)
def index = OpenOrScoped(_.Web.Mobile)(serveIndex)

private def serveIndex(using ctx: Context) = NoBot:
negotiate(
html =
pageHit
Expand Down
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ lazy val i18n = module("i18n",
I18n.serialize(
sourceDir = new File("translation/source"),
destDir = new File("translation/dest"),
dbs = "site arena emails learn activity coordinates study class contact appeal patron coach broadcast streamer tfa settings preferences team perfStat search tourname faq lag swiss puzzle puzzleTheme challenge storm ublog insight keyboardMove timeago oauthScope dgt voiceCommands onboarding features nvui video".split(' ').toList,
dbs = "site arena emails learn activity coordinates study class contact appeal patron coach broadcast streamer tfa settings practice preferences team perfStat search tourname faq lag swiss puzzle puzzleTheme challenge storm ublog insight keyboardMove timeago oauthScope dgt voiceCommands onboarding features nvui video".split(' ').toList,
outputDir = (Compile / resourceManaged).value
)
}.taskValue
Expand Down
1 change: 1 addition & 0 deletions conf/routes
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ GET /practice/:sectionId/:studySlug controllers.Practice.showStudy
GET /practice/:sectionId/:studySlug/:studyId controllers.Practice.show(sectionId, studySlug, studyId: StudyId)
GET /practice/:sectionId/:studySlug/:studyId/:chapterId controllers.Practice.showChapter(sectionId, studySlug, studyId: StudyId, chapterId: StudyChapterId)
POST /practice/complete/:chapterId/:moves controllers.Practice.complete(chapterId: StudyChapterId, moves: Int)
GET /$lang<\w\w\w?>/practice controllers.Practice.indexLang(lang: Language)

# Streamer
GET /streamer controllers.Streamer.index(page: Int ?= 1)
Expand Down
4 changes: 2 additions & 2 deletions modules/activity/src/main/ActivityReadApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import chess.Speed.Correspondence
final class ActivityReadApi(
coll: AsyncCollFailingSilently,
gameRepo: lila.core.game.GameRepo,
getPracticeStudies: lila.core.practice.GetStudies,
getPracticeStudies: lila.ui.practice.GetStudies,
forumPostApi: lila.core.forum.ForumPostApi,
ublogApi: lila.core.ublog.UblogApi,
simulApi: lila.core.simul.SimulApi,
Expand Down Expand Up @@ -51,7 +51,7 @@ final class ActivityReadApi(
_ <- getTourName.preload(views.flatMap(_.tours.so(_.best.map(_.tourId))))
yield ()

private def one(practiceStudies: Option[lila.core.practice.Studies], a: Activity): Fu[ActivityView] =
private def one(practiceStudies: Option[lila.ui.practice.Studies], a: Activity): Fu[ActivityView] =
for
allForumPosts <- a.forumPosts.traverse: p =>
forumPostApi
Expand Down
6 changes: 3 additions & 3 deletions modules/activity/src/main/ActivityUi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ final class ActivityUi(helpers: Helpers)(
)
)

private def renderPractice(p: Map[lila.core.practice.Study, Int])(using Context) =
private def renderPractice(p: Map[lila.ui.practice.Study, Int])(using Context) =
val ps = p.toSeq.sortBy(-_._2)
entryTag(
iconTag(Icon.Bullseye),
Expand All @@ -76,11 +76,11 @@ final class ActivityUi(helpers: Helpers)(
)
)

private def onePractice(tup: (lila.core.practice.Study, Int))(using Context) =
private def onePractice(tup: (lila.ui.practice.Study, Int))(using Context) =
val (study, nb) = tup
val href = routes.Practice.show("-", study.slug, study.id)
frag(
trans.activity.practicedNbPositions.plural(nb, nb, a(st.href := href)(study.name)),
trans.activity.practicedNbPositions.plural(nb, nb, a(st.href := href)(study.name())),
br
)

Expand Down
2 changes: 1 addition & 1 deletion modules/activity/src/main/ActivityView.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ case class ActivityView(
storm: Option[Storm] = None,
racer: Option[Racer] = None,
streak: Option[Streak] = None,
practice: Option[Map[lila.core.practice.Study, Int]] = None,
practice: Option[Map[lila.ui.practice.Study, Int]] = None,
simuls: Option[List[Simul]] = None,
patron: Option[Patron] = None,
forumPosts: Option[Map[ForumTopicMini, List[ForumPostMini]]] = None,
Expand Down
2 changes: 1 addition & 1 deletion modules/activity/src/main/ActivityWriteApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ final class ActivityWriteApi(
def learn(userId: UserId, stage: String) = update(userId): a =>
$doc(ActivityFields.learn -> { ~a.learn + LearnStage(stage) })

def practice(prog: lila.core.practice.OnComplete) = update(prog.userId): a =>
def practice(prog: lila.core.misc.practice.OnComplete) = update(prog.userId): a =>
$doc(ActivityFields.practice -> { ~a.practice + prog.studyId })

def simul(simul: Simul): Funit =
Expand Down
4 changes: 2 additions & 2 deletions modules/activity/src/main/Env.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import lila.core.round.CorresMoveEvent
@Module
final class Env(
db: lila.db.AsyncDb @@ lila.db.YoloDb,
practiceStudies: lila.core.practice.GetStudies,
practiceStudies: lila.ui.practice.GetStudies,
gameRepo: lila.core.game.GameRepo,
forumPostApi: lila.core.forum.ForumPostApi,
ublogApi: lila.core.ublog.UblogApi,
Expand Down Expand Up @@ -52,7 +52,7 @@ final class Env(

Bus.sub[lila.core.ublog.UblogPost.Create]: create =>
write.ublogPost(create.post)
Bus.sub[lila.core.practice.OnComplete](write.practice(_))
Bus.sub[lila.core.misc.practice.OnComplete](write.practice(_))
Bus.sub[lila.core.simul.OnStart]: start =>
write.simul(start.simul)
Bus.sub[CorresMoveEvent]:
Expand Down
7 changes: 5 additions & 2 deletions modules/activity/src/main/JsonView.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import lila.core.rating.{ RatingProg, Score }
import lila.core.simul.Simul
import lila.core.tournament.leaderboard.Ratio
import lila.rating.PerfType
import lila.core.i18n.Translate

final class JsonView(
getTourName: lila.core.tournament.GetTourName,
Expand Down Expand Up @@ -86,7 +87,9 @@ final class JsonView(
import Writers.{ *, given }

private given OWrites[lila.core.study.IdName] = Json.writes
def apply(a: ActivityView, user: User)(using Lang): Fu[JsObject] =

def apply(a: ActivityView, user: User)(using trans: Translate): Fu[JsObject] =
given Lang = trans.lang
fuccess:
Json
.obj("interval" -> a.interval)
Expand All @@ -101,7 +104,7 @@ final class JsonView(
a.practice.map(_.toList.sortBy(-_._2).map { (study, nb) =>
Json.obj(
"url" -> s"/practice/-/${study.slug}/${study.id}",
"name" -> study.name,
"name" -> study.name.txt(),
"nbPositions" -> nb
)
})
Expand Down
2 changes: 1 addition & 1 deletion modules/api/src/main/MobileApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ final class MobileApi(
Json.toJsObject(user) ++
lila.streamer.Stream.toJson(picfitUrl, stream)

def profile(user: User)(using me: Option[Me])(using Lang): Fu[JsObject] =
def profile(user: User)(using me: Option[Me])(using Translate): Fu[JsObject] =
for
prof <- userApi.mobile(user)
activities <- activityRead.recentAndPreload(user)
Expand Down
4 changes: 4 additions & 0 deletions modules/core/src/main/misc.scala
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,7 @@ trait PicfitUrl:
def raw(id: lila.core.id.ImageId): String

type BookmarkExists = (game.Game, Option[userId.UserId]) => Fu[Boolean]

package practice:
import lila.core.id.{ StudyId, StudyChapterId }
case class OnComplete(userId: UserId, studyId: StudyId, chapterId: StudyChapterId)
16 changes: 0 additions & 16 deletions modules/core/src/main/practice.scala

This file was deleted.

71 changes: 71 additions & 0 deletions modules/coreI18n/src/main/key.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,77 @@ object I18nKey:
val `maxTimePlaying`: I18nKey = "perfStat:maxTimePlaying"
val `now`: I18nKey = "perfStat:now"

object practice:
val `makesPerfect`: I18nKey = "practice:makesPerfect"
val `resetMyProgress`: I18nKey = "practice:resetMyProgress"
val `progressX`: I18nKey = "practice:progressX"
val `signUpToSaveYourProgress`: I18nKey = "practice:signUpToSaveYourProgress"
val `secHeadCheckmates`: I18nKey = "practice:secHeadCheckmates"
val `secHeadFundamentalTactics`: I18nKey = "practice:secHeadFundamentalTactics"
val `secHeadAdvancedTactics`: I18nKey = "practice:secHeadAdvancedTactics"
val `secHeadPawnEndgames`: I18nKey = "practice:secHeadPawnEndgames"
val `secHeadRookEndgames`: I18nKey = "practice:secHeadRookEndgames"
val `stNamPieceCheckmatesI`: I18nKey = "practice:stNamPieceCheckmatesI"
val `stNamCheckmatePatternsI`: I18nKey = "practice:stNamCheckmatePatternsI"
val `stNamCheckmatePatternsII`: I18nKey = "practice:stNamCheckmatePatternsII"
val `stNamCheckmatePatternsIII`: I18nKey = "practice:stNamCheckmatePatternsIII"
val `stNamCheckmatePatternsIV`: I18nKey = "practice:stNamCheckmatePatternsIV"
val `stNamPieceCheckmatesII`: I18nKey = "practice:stNamPieceCheckmatesII"
val `stNamKnightAndBishopMate`: I18nKey = "practice:stNamKnightAndBishopMate"
val `stNamThePin`: I18nKey = "practice:stNamThePin"
val `stNamTheSkewer`: I18nKey = "practice:stNamTheSkewer"
val `stNamTheFork`: I18nKey = "practice:stNamTheFork"
val `stNamDiscoveredAttacks`: I18nKey = "practice:stNamDiscoveredAttacks"
val `stNamDoubleCheck`: I18nKey = "practice:stNamDoubleCheck"
val `stNamOverloadedPieces`: I18nKey = "practice:stNamOverloadedPieces"
val `stNamZwischenzug`: I18nKey = "practice:stNamZwischenzug"
val `stNamXRay`: I18nKey = "practice:stNamXRay"
val `stNamZugzwang`: I18nKey = "practice:stNamZugzwang"
val `stNamInterference`: I18nKey = "practice:stNamInterference"
val `stNamGreekGift`: I18nKey = "practice:stNamGreekGift"
val `stNamDeflection`: I18nKey = "practice:stNamDeflection"
val `stNamAttraction`: I18nKey = "practice:stNamAttraction"
val `stNamUnderpromotion`: I18nKey = "practice:stNamUnderpromotion"
val `stNamDesperado`: I18nKey = "practice:stNamDesperado"
val `stNamCounterCheck`: I18nKey = "practice:stNamCounterCheck"
val `stNamUndermining`: I18nKey = "practice:stNamUndermining"
val `stNamClearance`: I18nKey = "practice:stNamClearance"
val `stNamKeySquares`: I18nKey = "practice:stNamKeySquares"
val `stNamOpposition`: I18nKey = "practice:stNamOpposition"
val `stNam7thRankRookPawn`: I18nKey = "practice:stNam7thRankRookPawn"
val `stNamBasicRookEndgames`: I18nKey = "practice:stNamBasicRookEndgames"
val `stNamIntermediateRookEndings`: I18nKey = "practice:stNamIntermediateRookEndings"
val `stNamPracticalRookEndings`: I18nKey = "practice:stNamPracticalRookEndings"
val `stDesBasicCheckmates`: I18nKey = "practice:stDesBasicCheckmates"
val `stDesRecognizeThePatterns`: I18nKey = "practice:stDesRecognizeThePatterns"
val `stDesChallengingCheckmates`: I18nKey = "practice:stDesChallengingCheckmates"
val `stDesInteractiveLesson`: I18nKey = "practice:stDesInteractiveLesson"
val `stDesPinItToWinIt`: I18nKey = "practice:stDesPinItToWinIt"
val `stDesYumSkewers`: I18nKey = "practice:stDesYumSkewers"
val `stDesUseTheForkLuke`: I18nKey = "practice:stDesUseTheForkLuke"
val `stDesIncludingDiscoveredChecks`: I18nKey = "practice:stDesIncludingDiscoveredChecks"
val `stDesAVeryPowerfulTactic`: I18nKey = "practice:stDesAVeryPowerfulTactic"
val `stDesTheyHaveTooMuchWork`: I18nKey = "practice:stDesTheyHaveTooMuchWork"
val `stDesInBetweenMoves`: I18nKey = "practice:stDesInBetweenMoves"
val `stDesAttackingThroughAnEnemyPiece`: I18nKey = "practice:stDesAttackingThroughAnEnemyPiece"
val `stDesBeingForcedToMove`: I18nKey = "practice:stDesBeingForcedToMove"
val `stDesInterposeAPieceToGreatEffect`: I18nKey = "practice:stDesInterposeAPieceToGreatEffect"
val `stDesStudyTheGreekGiftSacrifice`: I18nKey = "practice:stDesStudyTheGreekGiftSacrifice"
val `stDesDistractingADefender`: I18nKey = "practice:stDesDistractingADefender"
val `stDesLureAPieceToABadSquare`: I18nKey = "practice:stDesLureAPieceToABadSquare"
val `stDesPromoteButNotToAQueen`: I18nKey = "practice:stDesPromoteButNotToAQueen"
val `stDesAPieceIsLostButItCanStillHelp`: I18nKey = "practice:stDesAPieceIsLostButItCanStillHelp"
val `stDesRespondToACheckWithACheck`: I18nKey = "practice:stDesRespondToACheckWithACheck"
val `stDesRemoveTheDefendingPiece`: I18nKey = "practice:stDesRemoveTheDefendingPiece"
val `stDesGetOutOfTheWay`: I18nKey = "practice:stDesGetOutOfTheWay"
val `stDesReachAKeySquare`: I18nKey = "practice:stDesReachAKeySquare"
val `stDesTakeTheOpposition`: I18nKey = "practice:stDesTakeTheOpposition"
val `stDesVersusAQueen`: I18nKey = "practice:stDesVersusAQueen"
val `stDesAndPassiveRookVsRook`: I18nKey = "practice:stDesAndPassiveRookVsRook"
val `stDesLucenaAndPhilidor`: I18nKey = "practice:stDesLucenaAndPhilidor"
val `stDesBroadenYourKnowledge`: I18nKey = "practice:stDesBroadenYourKnowledge"
val `stDesRookEndingsWithSeveralPawns`: I18nKey = "practice:stDesRookEndingsWithSeveralPawns"

object preferences:
val `preferences`: I18nKey = "preferences:preferences"
val `display`: I18nKey = "preferences:display"
Expand Down
4 changes: 2 additions & 2 deletions modules/coreI18n/src/main/modules.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package lila.core.i18n

enum I18nModule:
case site, arena, emails, learn, activity, coordinates, study, `class`, contact, appeal, patron, coach,
broadcast, streamer, tfa, settings, preferences, team, perfStat, search, tourname, faq, lag, swiss,
puzzle, puzzleTheme, challenge, storm, ublog, insight, keyboardMove, timeago, oauthScope, dgt,
broadcast, streamer, tfa, settings, preferences, practice, team, perfStat, search, tourname, faq, lag,
swiss, puzzle, puzzleTheme, challenge, storm, ublog, insight, keyboardMove, timeago, oauthScope, dgt,
video, voiceCommands, onboarding, features, nvui
object I18nModule:
type Selector = I18nModule.type => I18nModule
2 changes: 1 addition & 1 deletion modules/practice/src/main/Env.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ final class Env(

lazy val api: PracticeApi = wire[PracticeApi]

def getStudies: lila.core.practice.GetStudies = api.structure.getStudies
def getStudies: lila.ui.practice.GetStudies = api.structure.getStudies
17 changes: 9 additions & 8 deletions modules/practice/src/main/JsonView.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@ package lila.practice
import play.api.libs.json.*

import lila.common.Json.{ *, given }
import lila.core.i18n.Translate

object JsonView:

case class JsData(study: JsObject, analysis: JsObject, practice: JsObject)

given Writes[PracticeProgress.NbMoves] = writeAs(_.value)
given Writes[PracticeStudy] = OWrites: ps =>
given (using Translate): Writes[PracticeStudy] = OWrites: ps =>
Json.obj(
"id" -> ps.id,
"name" -> ps.name,
"desc" -> ps.desc
"name" -> ps.name.txt(),
"desc" -> ps.desc.txt()
)
import PracticeGoal.*
given Writes[PracticeGoal] = OWrites:
Expand All @@ -24,19 +25,19 @@ object JsonView:
case EvalIn(cp, moves) => Json.obj("result" -> "evalIn", "cp" -> cp, "moves" -> moves)
case Promotion(cp) => Json.obj("result" -> "promotion", "cp" -> cp)

private given Writes[PracticeSection] = OWrites: sec =>
private given (using Translate): Writes[PracticeSection] = OWrites: sec =>
Json.obj(
"id" -> sec.id,
"name" -> sec.name,
"name" -> sec.name.txt(),
"studies" -> sec.studies.map: stu =>
Json.obj(
"id" -> stu.id,
"slug" -> stu.slug,
"name" -> stu.name
"name" -> stu.name.txt()
)
)

def apply(us: UserStudy) =
def apply(us: UserStudy)(using Translate) =
Json.obj(
"study" -> us.practiceStudy,
"url" -> us.url,
Expand All @@ -47,7 +48,7 @@ object JsonView:
"structure" -> us.practice.structure.sections
)

def api(us: UserPractice) = Json.obj(
def api(us: UserPractice)(using Translate) = Json.obj(
"sections" -> us.structure.sections,
"progress" -> us.progress.chapters
)
4 changes: 2 additions & 2 deletions modules/practice/src/main/PracticeApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ final class PracticeApi(
def get = cache.getUnit
def clear() = cache.invalidateUnit()

val getStudies: lila.core.practice.GetStudies = () => get.map(_.study)
val getStudies: lila.ui.practice.GetStudies = () => get.map(_.study)

object progress:

Expand All @@ -83,7 +83,7 @@ final class PracticeApi(
_ <- save(prog.withNbMoves(chapterId, score))
studyId <- studyApi.studyIdOf(chapterId)
yield studyId.so: studyId =>
Bus.pub(lila.core.practice.OnComplete(user.id, studyId, chapterId))
Bus.pub(lila.core.misc.practice.OnComplete(user.id, studyId, chapterId))

def reset(user: User) =
coll.delete.one($id(user.id)).void
Expand Down
Loading
Loading