ol-openedx-course-translations 0.3.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ol_openedx_course_translations-0.3.4/.gitignore +14 -0
- ol_openedx_course_translations-0.3.4/LICENSE.txt +28 -0
- ol_openedx_course_translations-0.3.4/PKG-INFO +409 -0
- ol_openedx_course_translations-0.3.4/README.rst +389 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/__init__.py +3 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/admin.py +29 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/apps.py +34 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/filters.py +39 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/glossaries/machine_learning/ar.txt +175 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/glossaries/machine_learning/de.txt +175 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/glossaries/machine_learning/el.txt +988 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/glossaries/machine_learning/es.txt +175 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/glossaries/machine_learning/fr.txt +175 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/glossaries/machine_learning/ja.txt +175 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/glossaries/machine_learning/pt-br.txt +175 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/glossaries/machine_learning/ru.txt +213 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/management/__init__.py +0 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/management/commands/__init__.py +0 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/management/commands/sync_and_translate_language.py +1866 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/management/commands/translate_course.py +585 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/middleware.py +143 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/migrations/0001_add_translation_logs.py +84 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/migrations/__init__.py +0 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/models.py +57 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/providers/__init__.py +1 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/providers/base.py +278 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/providers/deepl_provider.py +292 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/providers/llm_providers.py +581 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/settings/cms.py +17 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/settings/common.py +65 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/settings/lms.py +38 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/tasks.py +222 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/urls.py +16 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/utils/__init__.py +0 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/utils/command_utils.py +197 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/utils/constants.py +218 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/utils/course_translations.py +608 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/utils/translation_sync.py +808 -0
- ol_openedx_course_translations-0.3.4/ol_openedx_course_translations/views.py +73 -0
- ol_openedx_course_translations-0.3.4/pyproject.toml +45 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
Copyright (C) 2022 MIT Open Learning
|
|
2
|
+
|
|
3
|
+
All rights reserved.
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
* Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ol-openedx-course-translations
|
|
3
|
+
Version: 0.3.4
|
|
4
|
+
Summary: An Open edX plugin to translate courses
|
|
5
|
+
Author: MIT Office of Digital Learning
|
|
6
|
+
License-Expression: BSD-3-Clause
|
|
7
|
+
License-File: LICENSE.txt
|
|
8
|
+
Keywords: Python,edx
|
|
9
|
+
Requires-Python: >=3.11
|
|
10
|
+
Requires-Dist: deepl>=1.25.0
|
|
11
|
+
Requires-Dist: django>=4.0
|
|
12
|
+
Requires-Dist: djangorestframework>=3.14.0
|
|
13
|
+
Requires-Dist: edx-opaque-keys
|
|
14
|
+
Requires-Dist: gitpython>=3.1.40
|
|
15
|
+
Requires-Dist: litellm>=1.80.0
|
|
16
|
+
Requires-Dist: polib>=1.2.0
|
|
17
|
+
Requires-Dist: requests>=2.31.0
|
|
18
|
+
Requires-Dist: srt>=3.5.3
|
|
19
|
+
Description-Content-Type: text/x-rst
|
|
20
|
+
|
|
21
|
+
OL Open edX Course Translations
|
|
22
|
+
===============================
|
|
23
|
+
|
|
24
|
+
An Open edX plugin to manage course translations.
|
|
25
|
+
|
|
26
|
+
Purpose
|
|
27
|
+
*******
|
|
28
|
+
|
|
29
|
+
Translate course content into multiple languages to enhance accessibility for a global audience.
|
|
30
|
+
|
|
31
|
+
Setup
|
|
32
|
+
=====
|
|
33
|
+
|
|
34
|
+
For detailed installation instructions, please refer to the `plugin installation guide <../../docs#installation-guide>`_.
|
|
35
|
+
|
|
36
|
+
Installation required in:
|
|
37
|
+
|
|
38
|
+
* Studio (CMS)
|
|
39
|
+
* LMS (for auto language selection feature)
|
|
40
|
+
|
|
41
|
+
Configuration
|
|
42
|
+
=============
|
|
43
|
+
|
|
44
|
+
- Add the following configuration values to the config file in Open edX. For any release after Juniper, that config file is ``/edx/etc/lms.yml`` and ``/edx/etc/cms.yml``. If you're using ``private.py``, add these values to ``lms/envs/private.py`` and ``cms/envs/private.py``. These should be added to the top level. **Ask a fellow developer for these values.**
|
|
45
|
+
|
|
46
|
+
.. code-block:: python
|
|
47
|
+
|
|
48
|
+
# Enable auto language selection
|
|
49
|
+
ENABLE_AUTO_LANGUAGE_SELECTION: true
|
|
50
|
+
|
|
51
|
+
# Translation providers configuration
|
|
52
|
+
TRANSLATIONS_PROVIDERS: {
|
|
53
|
+
"default_provider": "mistral", # Default provider to use
|
|
54
|
+
"deepl": {
|
|
55
|
+
"api_key": "<YOUR_DEEPL_API_KEY>",
|
|
56
|
+
},
|
|
57
|
+
"openai": {
|
|
58
|
+
"api_key": "<YOUR_OPENAI_API_KEY>",
|
|
59
|
+
"default_model": "gpt-5.2",
|
|
60
|
+
},
|
|
61
|
+
"gemini": {
|
|
62
|
+
"api_key": "<YOUR_GEMINI_API_KEY>",
|
|
63
|
+
"default_model": "gemini-3-pro-preview",
|
|
64
|
+
},
|
|
65
|
+
"mistral": {
|
|
66
|
+
"api_key": "<YOUR_MISTRAL_API_KEY>",
|
|
67
|
+
"default_model": "mistral-large-latest",
|
|
68
|
+
},
|
|
69
|
+
}
|
|
70
|
+
TRANSLATIONS_GITHUB_TOKEN: <YOUR_GITHUB_TOKEN>
|
|
71
|
+
TRANSLATIONS_REPO_PATH: ""
|
|
72
|
+
TRANSLATIONS_REPO_URL: "https://github.com/mitodl/mitxonline-translations.git"
|
|
73
|
+
LITE_LLM_REQUEST_TIMEOUT: 120 # Timeout for LLM API requests in seconds
|
|
74
|
+
|
|
75
|
+
- For Tutor installations, these values can also be managed through a `custom Tutor plugin <https://docs.tutor.edly.io/tutorials/plugin.html#plugin-development-tutorial>`_.
|
|
76
|
+
|
|
77
|
+
Translation Providers
|
|
78
|
+
=====================
|
|
79
|
+
|
|
80
|
+
The plugin supports multiple translation providers:
|
|
81
|
+
|
|
82
|
+
- DeepL
|
|
83
|
+
- OpenAI (GPT models)
|
|
84
|
+
- Gemini (Google)
|
|
85
|
+
- Mistral
|
|
86
|
+
|
|
87
|
+
**Configuration**
|
|
88
|
+
|
|
89
|
+
All providers are configured through the ``TRANSLATIONS_PROVIDERS`` dictionary in your settings:
|
|
90
|
+
|
|
91
|
+
.. code-block:: python
|
|
92
|
+
|
|
93
|
+
TRANSLATIONS_PROVIDERS = {
|
|
94
|
+
"default_provider": "mistral", # Optional: default provider for commands
|
|
95
|
+
"deepl": {
|
|
96
|
+
"api_key": "<YOUR_DEEPL_API_KEY>",
|
|
97
|
+
},
|
|
98
|
+
"openai": {
|
|
99
|
+
"api_key": "<YOUR_OPENAI_API_KEY>",
|
|
100
|
+
"default_model": "gpt-5.2", # Optional: used when model not specified
|
|
101
|
+
},
|
|
102
|
+
"gemini": {
|
|
103
|
+
"api_key": "<YOUR_GEMINI_API_KEY>",
|
|
104
|
+
"default_model": "gemini-3-pro-preview",
|
|
105
|
+
},
|
|
106
|
+
"mistral": {
|
|
107
|
+
"api_key": "<YOUR_MISTRAL_API_KEY>",
|
|
108
|
+
"default_model": "mistral-large-latest",
|
|
109
|
+
},
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
**Important Notes:**
|
|
113
|
+
|
|
114
|
+
1. **DeepL Configuration**: DeepL must be configured in ``TRANSLATIONS_PROVIDERS['deepl']['api_key']``.
|
|
115
|
+
|
|
116
|
+
2. **DeepL for Subtitle Repair**: DeepL is used as a fallback repair mechanism for subtitle translations when LLM providers fail validation. Even if you use LLM providers for primary translation, you should configure DeepL to enable automatic repair.
|
|
117
|
+
|
|
118
|
+
3. **Default Models**: The ``default_model`` in each provider's configuration is used when you specify a provider without a model (e.g., ``openai`` instead of ``openai/gpt-5.2``).
|
|
119
|
+
|
|
120
|
+
**Provider Selection**
|
|
121
|
+
|
|
122
|
+
You can specify providers in three ways:
|
|
123
|
+
|
|
124
|
+
1. **Provider only** (uses default model from settings):
|
|
125
|
+
|
|
126
|
+
.. code-block:: bash
|
|
127
|
+
|
|
128
|
+
./manage.py cms translate_course \
|
|
129
|
+
--target-language AR \
|
|
130
|
+
--course-dir /path/to/course.tar.gz \
|
|
131
|
+
--content-translation-provider openai \
|
|
132
|
+
--srt-translation-provider gemini
|
|
133
|
+
|
|
134
|
+
2. **Provider with specific model**:
|
|
135
|
+
|
|
136
|
+
.. code-block:: bash
|
|
137
|
+
|
|
138
|
+
./manage.py cms translate_course \
|
|
139
|
+
--target-language AR \
|
|
140
|
+
--course-dir /path/to/course.tar.gz \
|
|
141
|
+
--content-translation-provider openai/gpt-5.2 \
|
|
142
|
+
--srt-translation-provider gemini/gemini-3-pro-preview
|
|
143
|
+
|
|
144
|
+
3. **DeepL** (no model needed):
|
|
145
|
+
|
|
146
|
+
.. code-block:: bash
|
|
147
|
+
|
|
148
|
+
./manage.py cms translate_course \
|
|
149
|
+
--target-language AR \
|
|
150
|
+
--course-dir /path/to/course.tar.gz \
|
|
151
|
+
--content-translation-provider deepl \
|
|
152
|
+
--srt-translation-provider deepl
|
|
153
|
+
|
|
154
|
+
**Note:** If you specify a provider without a model (e.g., ``openai`` instead of ``openai/gpt-5.2``), the system will use the ``default_model`` configured in ``TRANSLATIONS_PROVIDERS`` for that provider.
|
|
155
|
+
|
|
156
|
+
Translating a Course
|
|
157
|
+
====================
|
|
158
|
+
1. Open the course in Studio.
|
|
159
|
+
2. Go to Tools -> Export Course.
|
|
160
|
+
3. Export the course as a .tar.gz file.
|
|
161
|
+
4. Go to the CMS shell
|
|
162
|
+
5. Run the management command to translate the course:
|
|
163
|
+
|
|
164
|
+
.. code-block:: bash
|
|
165
|
+
|
|
166
|
+
./manage.py cms translate_course \
|
|
167
|
+
--source-language EN \
|
|
168
|
+
--target-language AR \
|
|
169
|
+
--course-dir /path/to/course.tar.gz \
|
|
170
|
+
--content-translation-provider openai \
|
|
171
|
+
--srt-translation-provider gemini \
|
|
172
|
+
--glossary-dir /path/to/glossary
|
|
173
|
+
|
|
174
|
+
**Command Options:**
|
|
175
|
+
|
|
176
|
+
- ``--source-language``: Source language code (default: EN)
|
|
177
|
+
- ``--target-language``: Target language code (required)
|
|
178
|
+
- ``--course-dir``: Path to exported course tar.gz file (required)
|
|
179
|
+
- ``--content-translation-provider``: Translation provider for content (XML/HTML and text) (required).
|
|
180
|
+
|
|
181
|
+
Format:
|
|
182
|
+
|
|
183
|
+
- ``deepl`` - uses DeepL (no model needed)
|
|
184
|
+
- ``PROVIDER`` - uses provider with default model from settings (e.g., ``openai``, ``gemini``, ``mistral``)
|
|
185
|
+
- ``PROVIDER/MODEL`` - uses provider with specific model (e.g., ``openai/gpt-5.2``, ``gemini/gemini-3-pro-preview``, ``mistral/mistral-large-latest``)
|
|
186
|
+
|
|
187
|
+
- ``--srt-translation-provider``: Translation provider for SRT subtitles (required). Same format as ``--content-translation-provider``
|
|
188
|
+
- ``--glossary-dir``: Path to glossary directory (optional)
|
|
189
|
+
|
|
190
|
+
**Examples:**
|
|
191
|
+
|
|
192
|
+
.. code-block:: bash
|
|
193
|
+
|
|
194
|
+
# Use DeepL for both content and subtitles
|
|
195
|
+
./manage.py cms translate_course \
|
|
196
|
+
--target-language AR \
|
|
197
|
+
--course-dir /path/to/course.tar.gz \
|
|
198
|
+
--content-translation-provider deepl \
|
|
199
|
+
--srt-translation-provider deepl
|
|
200
|
+
|
|
201
|
+
# Use OpenAI and Gemini with default models from settings
|
|
202
|
+
./manage.py cms translate_course \
|
|
203
|
+
--target-language FR \
|
|
204
|
+
--course-dir /path/to/course.tar.gz \
|
|
205
|
+
--content-translation-provider openai \
|
|
206
|
+
--srt-translation-provider gemini
|
|
207
|
+
|
|
208
|
+
# Use OpenAI with specific model for content, Gemini with default for subtitles
|
|
209
|
+
./manage.py cms translate_course \
|
|
210
|
+
--target-language FR \
|
|
211
|
+
--course-dir /path/to/course.tar.gz \
|
|
212
|
+
--content-translation-provider openai/gpt-5.2 \
|
|
213
|
+
--srt-translation-provider gemini
|
|
214
|
+
|
|
215
|
+
# Use Mistral with specific model and glossary
|
|
216
|
+
./manage.py cms translate_course \
|
|
217
|
+
--target-language ES \
|
|
218
|
+
--course-dir /path/to/course.tar.gz \
|
|
219
|
+
--content-translation-provider mistral/mistral-large-latest \
|
|
220
|
+
--srt-translation-provider mistral/mistral-large-latest \
|
|
221
|
+
--glossary-dir /path/to/glossary
|
|
222
|
+
|
|
223
|
+
**Glossary Support:**
|
|
224
|
+
|
|
225
|
+
Create language-specific glossary files in the glossary directory:
|
|
226
|
+
|
|
227
|
+
.. code-block:: bash
|
|
228
|
+
|
|
229
|
+
glossaries/machine_learning/
|
|
230
|
+
├── ar.txt # Arabic glossary
|
|
231
|
+
├── fr.txt # French glossary
|
|
232
|
+
└── es.txt # Spanish glossary
|
|
233
|
+
|
|
234
|
+
Format: One term per line as "source_term : translated_term"
|
|
235
|
+
|
|
236
|
+
.. code-block:: text
|
|
237
|
+
|
|
238
|
+
# ES HINTS
|
|
239
|
+
## TERM MAPPINGS
|
|
240
|
+
These are preferred terminology choices for this language. Use them whenever they sound natural; adapt freely if context requires.
|
|
241
|
+
|
|
242
|
+
- 'accuracy' : 'exactitud'
|
|
243
|
+
- 'activation function' : 'función de activación'
|
|
244
|
+
- 'artificial intelligence' : 'inteligencia artificial'
|
|
245
|
+
- 'AUC' : 'AUC'
|
|
246
|
+
|
|
247
|
+
Subtitle Translation and Validation
|
|
248
|
+
====================================
|
|
249
|
+
|
|
250
|
+
The course translation system includes robust subtitle (SRT) translation with automatic validation and repair mechanisms to ensure high-quality translations with preserved timing information.
|
|
251
|
+
|
|
252
|
+
**Translation Process**
|
|
253
|
+
|
|
254
|
+
The subtitle translation follows a multi-stage process with built-in quality checks:
|
|
255
|
+
|
|
256
|
+
1. **Initial Translation**: Subtitles are translated using your configured provider (DeepL or LLM)
|
|
257
|
+
2. **Validation**: Timestamps, subtitle count, and content are validated to ensure integrity
|
|
258
|
+
3. **Automatic Retry**: If validation fails, the system automatically retries translation (up to 1 additional attempt)
|
|
259
|
+
4. **DeepL Repair Fallback**: If retries fail, the system automatically falls back to DeepL for repair
|
|
260
|
+
|
|
261
|
+
**Why DeepL for Repair?**
|
|
262
|
+
|
|
263
|
+
When subtitle translations fail validation (mismatched timestamps, incorrect subtitle counts, or blank translations), the system automatically uses **DeepL as a repair mechanism**, regardless of which provider was initially used. This design choice is based on extensive testing and production experience:
|
|
264
|
+
|
|
265
|
+
- **Higher Reliability**: LLMs frequently fail to preserve subtitle structure and timestamps correctly, even with detailed prompting
|
|
266
|
+
- **Consistent Formatting**: DeepL's specialized subtitle translation API maintains timing precision through XML tag handling
|
|
267
|
+
- **Lower Failure Rate**: DeepL demonstrates significantly better success rates for subtitle translation compared to LLMs
|
|
268
|
+
- **Timestamp Preservation**: DeepL's built-in XML tag handling ensures start and end times remain intact during translation
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
**Validation Rules**
|
|
272
|
+
|
|
273
|
+
The system validates subtitle translations against these criteria:
|
|
274
|
+
|
|
275
|
+
- **Subtitle Count**: Translated file must have the same number of subtitle blocks as the original
|
|
276
|
+
- **Index Matching**: Each subtitle block index must match the original (e.g., if original has blocks 1-100, translation must have blocks 1-100 in the same order)
|
|
277
|
+
- **Timestamp Preservation**: Start and end times for each subtitle block must remain unchanged
|
|
278
|
+
- **Content Validation**: Non-empty original subtitles must have non-empty translations (blank translations are flagged as errors)
|
|
279
|
+
|
|
280
|
+
**Example Validation Process:**
|
|
281
|
+
|
|
282
|
+
.. code-block:: text
|
|
283
|
+
|
|
284
|
+
1. Initial Translation (using OpenAI):
|
|
285
|
+
✓ 150 subtitle blocks translated
|
|
286
|
+
✗ Validation failed: 3 blocks have mismatched timestamps
|
|
287
|
+
|
|
288
|
+
2. Retry Attempt:
|
|
289
|
+
✓ 150 subtitle blocks translated
|
|
290
|
+
✗ Validation failed: 2 blocks still have issues
|
|
291
|
+
|
|
292
|
+
3. DeepL Repair:
|
|
293
|
+
✓ 150 subtitle blocks retranslated using DeepL
|
|
294
|
+
✓ Validation passed: All timestamps and content validated
|
|
295
|
+
✅ Translation completed successfully
|
|
296
|
+
|
|
297
|
+
**Failure Handling**
|
|
298
|
+
|
|
299
|
+
If subtitle repair fails after all attempts (including DeepL fallback):
|
|
300
|
+
|
|
301
|
+
- The translation task will fail with a ``ValueError``
|
|
302
|
+
- The entire course translation will be aborted to prevent incomplete translations
|
|
303
|
+
- The translated course directory will be automatically cleaned up
|
|
304
|
+
- An error message will indicate which subtitle file caused the failure
|
|
305
|
+
- No partial or corrupted translation files will be left behind
|
|
306
|
+
|
|
307
|
+
Auto Language Selection
|
|
308
|
+
=======================
|
|
309
|
+
|
|
310
|
+
The plugin includes an auto language selection feature that automatically sets the user's language preference based on the course language. When enabled, users will see the static site content in the course's configured language.
|
|
311
|
+
|
|
312
|
+
To enable auto language selection:
|
|
313
|
+
|
|
314
|
+
1. Set ``ENABLE_AUTO_LANGUAGE_SELECTION`` to ``true`` in your settings.
|
|
315
|
+
|
|
316
|
+
2. Set ``SHARED_COOKIE_DOMAIN`` to your domain (e.g., ``.local.openedx.io`` for local tutor setup) to allow cookies to be shared between LMS and CMS.
|
|
317
|
+
|
|
318
|
+
**How it works:**
|
|
319
|
+
|
|
320
|
+
- **LMS**: The ``CourseLanguageCookieMiddleware`` automatically detects course URLs and sets the language preference based on the course's configured language.
|
|
321
|
+
- **CMS**: The ``CourseLanguageCookieResetMiddleware`` ensures Studio always uses English for the authoring interface.
|
|
322
|
+
- **Admin areas**: Admin URLs (``/admin``, ``/sysadmin``, instructor dashboards) are forced to use English regardless of course language.
|
|
323
|
+
|
|
324
|
+
MFE Integration
|
|
325
|
+
===============
|
|
326
|
+
|
|
327
|
+
To make auto language selection work with Micro-Frontends (MFEs), you need to use a custom Footer component that handles language detection and switching.
|
|
328
|
+
|
|
329
|
+
**Setup:**
|
|
330
|
+
|
|
331
|
+
1. Use the Footer component from `src/bridge/settings/openedx/mfe/slot_config/Footer.jsx <https://github.com/mitodl/ol-infrastructure/blob/main/src/bridge/settings/openedx/mfe/slot_config/Footer.jsx>`_ in the `ol-infrastructure <https://github.com/mitodl/ol-infrastructure>`_ repository.
|
|
332
|
+
|
|
333
|
+
2. Enable auto language selection in each MFE by adding the following to their ``.env.development`` file:
|
|
334
|
+
|
|
335
|
+
.. code-block:: bash
|
|
336
|
+
|
|
337
|
+
ENABLE_AUTO_LANGUAGE_SELECTION="true"
|
|
338
|
+
|
|
339
|
+
3. This custom Footer component:
|
|
340
|
+
- Detects the current course context in MFEs
|
|
341
|
+
- Automatically switches the MFE language based on the course's configured language
|
|
342
|
+
- Ensures consistent language experience across the platform
|
|
343
|
+
|
|
344
|
+
4. Configure your MFE slot overrides to use this custom Footer component instead of the default one.
|
|
345
|
+
|
|
346
|
+
**Note:** The custom Footer is required because MFEs run as separate applications and need their own mechanism to detect and respond to course language settings. The environment variable must be set in each MFE's configuration for the feature to work properly.
|
|
347
|
+
|
|
348
|
+
Generating static content translations
|
|
349
|
+
======================================
|
|
350
|
+
|
|
351
|
+
This command synchronizes translation keys from edx-platform and MFE's, translates empty keys using LLM, and automatically creates a pull request in the translations repository.
|
|
352
|
+
|
|
353
|
+
**What it does:**
|
|
354
|
+
|
|
355
|
+
1. Syncs translation keys from edx-platform and MFE's to the translations repository
|
|
356
|
+
2. Extracts empty translation keys that need translation
|
|
357
|
+
3. Translates empty keys using the specified LLM provider and model
|
|
358
|
+
4. Applies translations to JSON and PO files
|
|
359
|
+
5. Commits changes to a new branch
|
|
360
|
+
6. Creates a pull request with translation statistics
|
|
361
|
+
|
|
362
|
+
**Usage:**
|
|
363
|
+
|
|
364
|
+
1. Go to the CMS shell
|
|
365
|
+
2. Run the management command:
|
|
366
|
+
|
|
367
|
+
.. code-block:: bash
|
|
368
|
+
|
|
369
|
+
./manage.py cms sync_and_translate_language <LANGUAGE_CODE> [OPTIONS]
|
|
370
|
+
|
|
371
|
+
**Required arguments:**
|
|
372
|
+
|
|
373
|
+
- ``LANGUAGE_CODE``: Language code (e.g., ``el``, ``fr``, ``es_ES``)
|
|
374
|
+
|
|
375
|
+
**Optional arguments:**
|
|
376
|
+
|
|
377
|
+
- ``--iso-code``: ISO code for JSON files (default: same as language code)
|
|
378
|
+
- ``--provider``: Translation provider (``openai``, ``gemini``, ``mistral``). Default is taken from ``TRANSLATIONS_PROVIDERS['default_provider']`` setting
|
|
379
|
+
- ``--model``: LLM model name. If not specified, uses the ``default_model`` for the selected provider from ``TRANSLATIONS_PROVIDERS``. Examples: ``gpt-5.2``, ``gemini-3-pro-preview``, ``mistral-large-latest``
|
|
380
|
+
- ``--repo-path``: Path to mitxonline-translations repository (can also be set via ``TRANSLATIONS_REPO_PATH`` setting or environment variable)
|
|
381
|
+
- ``--repo-url``: GitHub repository URL (default: ``https://github.com/mitodl/mitxonline-translations.git``, can also be set via ``TRANSLATIONS_REPO_URL`` setting or environment variable)
|
|
382
|
+
- ``--glossary``: Use glossary from plugin glossaries folder (looks for ``{plugin_dir}/glossaries/machine_learning/{lang_code}.txt``)
|
|
383
|
+
- ``--batch-size``: Number of keys to translate per API request (default: 200, recommended: 200-300 for most models)
|
|
384
|
+
- ``--mfe``: Filter by specific MFE(s). Use ``edx-platform`` for backend translations
|
|
385
|
+
- ``--dry-run``: Run without committing or creating PR
|
|
386
|
+
|
|
387
|
+
**Examples:**
|
|
388
|
+
|
|
389
|
+
.. code-block:: bash
|
|
390
|
+
|
|
391
|
+
# Use default provider (from TRANSLATIONS_PROVIDERS['default_provider']) with its default model
|
|
392
|
+
./manage.py cms sync_and_translate_language el
|
|
393
|
+
|
|
394
|
+
# Use OpenAI provider with its default model (gpt-5.2)
|
|
395
|
+
./manage.py cms sync_and_translate_language el --provider openai
|
|
396
|
+
|
|
397
|
+
# Use OpenAI provider with a specific model
|
|
398
|
+
./manage.py cms sync_and_translate_language el --provider openai --model gpt-5.2
|
|
399
|
+
|
|
400
|
+
# Use Mistral provider with a specific model and glossary
|
|
401
|
+
./manage.py cms sync_and_translate_language el --provider mistral --model mistral-large-latest --glossary --batch-size 250
|
|
402
|
+
|
|
403
|
+
License
|
|
404
|
+
*******
|
|
405
|
+
|
|
406
|
+
The code in this repository is licensed under the AGPL 3.0 unless
|
|
407
|
+
otherwise noted.
|
|
408
|
+
|
|
409
|
+
Please see `LICENSE.txt <LICENSE.txt>`_ for details.
|