Skip to content
Open
Show file tree
Hide file tree
Changes from 6 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".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".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 @@ -341,6 +341,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
14 changes: 14 additions & 0 deletions modules/coreI18n/src/main/key.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1138,6 +1138,20 @@ object I18nKey:
val `maxTimePlaying`: I18nKey = "perfStat:maxTimePlaying"
val `now`: I18nKey = "perfStat:now"

object practice:
val `practice`: I18nKey = "practice:practice"
val `practiceChess`: I18nKey = "practice:practiceChess"
val `makesPerfect`: I18nKey = "practice:makesPerfect"
val `resetMyProgress`: I18nKey = "practice:resetMyProgress"
val `progressX`: I18nKey = "practice:progressX"
val `youWillLoseYourPracticeProgress`: I18nKey = "practice:youWillLoseYourPracticeProgress"
var `signUpToSaveYourProgress`: I18nKey = "practice:signUpToSaveYourProgress"
val `secHeadCheckmates`: I18nKey = "practice:secHeadCheckmates"
val `secHeadBasicTactics`: I18nKey = "practice:secHeadBasicTactics"
val `secHeadIntermediateTactics`: I18nKey = "practice:secHeadIntermediateTactics"
val `secHeadPawnEndgames`: I18nKey = "practice:secHeadPawnEndgames"
val `secHeadRookEndgames`: I18nKey = "practice:secHeadRookEndgames"

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,
voiceCommands, onboarding, features, nvui
object I18nModule:
type Selector = I18nModule.type => I18nModule
34 changes: 22 additions & 12 deletions modules/practice/src/main/PracticeUi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ final class PracticeUi(helpers: Helpers)(
modMenu: Context ?=> Frag
):
import helpers.{ *, given }
import trans.practice as trp

def show(us: UserStudy, data: JsonView.JsData)(using ctx: Context) =
Page(us.practiceStudy.name.value)
.css("analyse.practice")
.i18n(_.puzzle, _.study)
.i18nOpt(ctx.pref.hasSpeech || ctx.blind, _.nvui)
.i18nOpt(ctx.blind, _.keyboardMove)
.i18n(_.practice, _.puzzle, _.study)
.i18nOpt(ctx.blind, _.keyboardMove, _.nvui)
.js(analyseNvuiTag)
.js(
PageModule(
Expand All @@ -37,8 +37,17 @@ final class PracticeUi(helpers: Helpers)(
main(cls := "analyse")

def index(data: lila.practice.UserPractice)(using ctx: Context) =
Page("Practice chess positions")
def sectionHeader(name: String): RawFrag = name match
case "Checkmates" => trp.secHeadCheckmates()
case "Basic Tactics" => trp.secHeadBasicTactics()
case "Intermediate Tactics" => trp.secHeadIntermediateTactics()
case "Pawn Endgames" => trp.secHeadPawnEndgames()
case "Rook Endgames" => trp.secHeadRookEndgames()
case other => RawFrag(other)

Page(s"${trp.practiceChess.txt()} - ${trp.makesPerfect.txt()}")
.css("bits.practice.index")
.i18n(_.practice)
.graph(
title = "Practice your chess",
description = "Learn how to master the most common chess positions",
Expand All @@ -47,33 +56,33 @@ final class PracticeUi(helpers: Helpers)(
main(cls := "page-menu force-ltr")(
st.aside(cls := "page-menu__menu practice-side")(
i(cls := "fat"),
h1("Practice"),
h2("makes your chess perfect"),
h1(trp.practice()),
h2(trp.makesPerfect()),
div(cls := "progress")(
div(cls := "text")("Progress: ", data.progressPercent, "%"),
div(cls := "text")(trp.progressX(data.progressPercent.toString() + "%")),
div(cls := "bar", style := s"width: ${data.progressPercent}%")
),
postForm(action := routes.Practice.reset)(
if ctx.isAuth then
(data.nbDoneChapters > 0).option(
submitButton(
cls := "button ok-cancel-confirm",
title := "You will lose your practice progress!"
)("Reset my progress")
title := trp.youWillLoseYourPracticeProgress.txt()
)(trp.resetMyProgress())
)
else a(href := routes.Auth.signup)("Sign up to save your progress")
else a(href := routes.Auth.signup)(trp.signUpToSaveYourProgress())
)
),
div(cls := "page-menu__content practice-app")(
data.structure.sections.filter(s => !s.hide || Granter.opt(_.PracticeConfig)).map { section =>
st.section(
h2(section.name),
h2(sectionHeader(section.name)),
div(cls := "studies")(
section.studies.filter(s => !s.hide || Granter.opt(_.PracticeConfig)).map { stud =>
val prog = data.progressOn(stud.id)
a(
cls := s"study ${if prog.complete then "done" else "ongoing"}",
href := routes.Practice.show(section.id, stud.slug, stud.id)
href := routes.Practice.show(section.id, stud.slug, stud.id) // TODO: langHref
)(
ctx.isAuth.option(
span(cls := "ribbon-wrapper")(
Expand All @@ -92,6 +101,7 @@ final class PracticeUi(helpers: Helpers)(
}
)
)
.hrefLangs(lila.ui.LangPath(routes.Practice.index))

def config(structure: lila.practice.PracticeStructure, form: Form[?])(using Context) =
Page("Practice structure").css("mod.misc"):
Expand Down
2 changes: 1 addition & 1 deletion modules/web/src/main/ui/TopNav.scala
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ final class TopNav(helpers: Helpers):
Option.when(ctx.noBot):
frag(
a(href := langHref(routes.Learn.index))(trans.site.chessBasics()),
a(href := routes.Practice.index)(trans.site.practice()),
a(href := langHref(routes.Practice.index))(trans.site.practice()),
a(href := langHref(routes.Coordinate.home))(trans.coordinates.coordinates())
)
,
Expand Down
15 changes: 15 additions & 0 deletions translation/dest/practice/en-US.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="practice">Practice</string>
<string name="practiceChess">Practice chess</string>
<string name="makesPerfect">makes your chess perfect</string>
<string name="resetMyProgress">Reset my progress</string>
<string name="progressX">Progress: %s</string>
<string name="youWillLoseYourPracticeProgress">You will lose your practice progress!</string>
<string name="signUpToSaveYourProgress">Sign up to save your progress</string>
<string name="secHeadCheckmates">Checkmates</string>
<string name="secHeadBasicTactics">Basic Tactics</string>
<string name="secHeadIntermediateTactics">Intermediate Tactics</string>
<string name="secHeadPawnEndgames">Pawn Endgames</string>
<string name="secHeadRookEndgames">Rook Endgames</string>
</resources>
15 changes: 15 additions & 0 deletions translation/dest/practice/ru-RU.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="practice">Практика</string>
<string name="practiceChess">Практика шахмат</string>
<string name="makesPerfect">способствует повышению уровня игры</string>
<string name="resetMyProgress">Начать всё с начала</string>
<string name="progressX">Пройдено: %s</string>
<string name="youWillLoseYourPracticeProgress">Все ваши успехи обнулятся!</string>
<string name="signUpToSaveYourProgress">Авторизуйтесь для сохранения прогресса</string>
<string name="secHeadCheckmates">Матование</string>
<string name="secHeadBasicTactics">Основы тактики</string>
<string name="secHeadIntermediateTactics">Промежуточная Тактика</string>
<string name="secHeadPawnEndgames">Пешечные окончания</string>
<string name="secHeadRookEndgames">Ладейные окончания</string>
</resources>
15 changes: 15 additions & 0 deletions translation/source/practice.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<string name="practice">Practice</string>
<string name="practiceChess">Practice chess</string>
<string name="makesPerfect">makes your chess perfect</string>
<string name="resetMyProgress">Reset my progress</string>
<string name="progressX">Progress: %s</string>
<string name="youWillLoseYourPracticeProgress">You will lose your practice progress!</string>
<string name="signUpToSaveYourProgress">Sign up to save your progress</string>
<string name="secHeadCheckmates">Checkmates</string>
<string name="secHeadBasicTactics">Basic Tactics</string>
<string name="secHeadIntermediateTactics">Intermediate Tactics</string>
<string name="secHeadPawnEndgames">Pawn Endgames</string>
<string name="secHeadRookEndgames">Rook Endgames</string>
</resources>
26 changes: 26 additions & 0 deletions ui/@types/lichess/i18n.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2206,6 +2206,32 @@ interface I18n {
/** Winning streak */
winningStreak: string;
};
practice: {
/** makes your chess perfect */
makesPerfect: string;
/** Practice */
practice: string;
/** Practice chess */
practiceChess: string;
/** Progress: %s */
progressX: I18nFormat;
/** Reset my progress */
resetMyProgress: string;
/** You will lose your practice progress! */
youWillLoseYourPracticeProgress: string;
/** Sign up to save your progress */
signUpToSaveYourProgress: string;
/** Checkmates */
secHeadCheckmates: string;
/** Basic Tactics */
secHeadBasicTactics: string;
/** Intermediate Tactics */
secHeadIntermediateTactics: string;
/** Pawn Endgames */
secHeadPawnEndgames: string;
/** Rook Endgames */
secHeadRookEndgames: string;
};
preferences: {
/** Bell notification sound */
bellNotificationSound: string;
Expand Down
Loading