From 87cc50640a9d2512b478d491c8313e3a98df4c25 Mon Sep 17 00:00:00 2001 From: Richard Tibbles Date: Sat, 15 Aug 2026 16:21:52 -0700 Subject: [PATCH 1/2] Run plugin discovery under the project virtualenv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit webpack_json.py imports each plugin module to find its buildConfig.js, so it needs the interpreter the plugins are installed into. A bare `python` is the system interpreter wherever the build runs outside an activated shell, and the python_packages/* members are not importable there — the Crowdin upload failed on kolibri_demo_server_plugin for exactly this reason, one line after the Makefile's `uv run python -c "import ..."` guard had passed. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01HkePtEQUF73hQuovbiQ85Q --- .../kolibri-build/src/read_webpack_json.js | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/packages/kolibri-build/src/read_webpack_json.js b/packages/kolibri-build/src/read_webpack_json.js index 19b61e00c5d..2d7f54cb653 100644 --- a/packages/kolibri-build/src/read_webpack_json.js +++ b/packages/kolibri-build/src/read_webpack_json.js @@ -5,6 +5,31 @@ const temp = require('temp').track(); const webpack_json = path.resolve(path.dirname(__filename), './webpack_json.py'); +const VENV_PYTHON = process.platform === 'win32' ? ['Scripts', 'python.exe'] : ['bin', 'python']; + +// uv puts the project environment in `.venv` unless UV_PROJECT_ENVIRONMENT overrides it, +// and resolves a relative override against the project root. +const PROJECT_VENV = process.env.UV_PROJECT_ENVIRONMENT || '.venv'; + +// webpack_json.py has to import the plugin modules, so it needs the interpreter they are +// installed into. A bare `python` is the system interpreter whenever the build runs +// outside an activated shell — CI calling `make`, an editor task runner — and there the +// plugins are not importable at all. +function resolvePython() { + if (process.env.VIRTUAL_ENV) { + return path.join(process.env.VIRTUAL_ENV, ...VENV_PYTHON); + } + for (let dir = process.cwd(); ; dir = path.dirname(dir)) { + const candidate = path.join(path.resolve(dir, PROJECT_VENV), ...VENV_PYTHON); + if (fs.existsSync(candidate)) { + return candidate; + } + if (path.dirname(dir) === dir) { + return 'python'; + } + } +} + function parseConfig(buildConfig, pythonData, configPath, index = null) { // Set the bundleId by a concatenation of the Python module path // And the specified bundle_id that should be unique within this plugin. @@ -42,7 +67,7 @@ function readPythonPlugins({ pluginFile, plugins, pluginPath }) { args.push('--plugin_path', pluginPath); } } - execFileSync('python', args); + execFileSync(resolvePython(), args); const result = fs.readFileSync(webpack_json_tempfile); From 2e62d19b2e6707539e0668575564b7bbd3acf307 Mon Sep 17 00:00:00 2001 From: Richard Tibbles Date: Sat, 15 Aug 2026 16:22:06 -0700 Subject: [PATCH 2/2] Stop extracting frontend messages from test files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit __tests__ was in scope for the extraction glob, so every spec calling createTranslator(Component.name, ...) logged an unresolvable-namespace error — 33 of them per run. Worse, AssessmentWrapper.spec.js declares PerseusRendererIndex hint/noMoreHint with literal messages and no context, which overwrote the real definitions: both strings have been reaching Crowdin with an empty Context field. checkForDuplicateIds compares message only, so it never flagged the collision. Same 5839 identifiers extract either way; the two strings regain their context. LearnerExerciseReport's empty $trs went with it, being the last warning left. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01HkePtEQUF73hQuovbiQ85Q --- .../coach/frontend/views/common/LearnerExerciseReport.vue | 1 - pyproject.toml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/kolibri/plugins/coach/frontend/views/common/LearnerExerciseReport.vue b/kolibri/plugins/coach/frontend/views/common/LearnerExerciseReport.vue index 72034e44ad6..bc2ff256c39 100644 --- a/kolibri/plugins/coach/frontend/views/common/LearnerExerciseReport.vue +++ b/kolibri/plugins/coach/frontend/views/common/LearnerExerciseReport.vue @@ -76,7 +76,6 @@ }); }, }, - $trs: {}, }; diff --git a/pyproject.toml b/pyproject.toml index 9e342ca0d9b..27e6677deb0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -219,4 +219,4 @@ exclude_lines = [ [tool.kolibri.i18n] project = "kolibri" locale_data_folder = "kolibri/locale" -ignore = "**/node_modules/**,**/static/**" +ignore = "**/node_modules/**,**/static/**,**/__tests__/**"