diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e26f73f449..d2f84ade2c 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -21,11 +21,12 @@ updates: cooldown: default-days: 7 exclude: + - kolibri-build - kolibri-constants - kolibri-design-system - - kolibri-logging - kolibri-format - - kolibri-tools + - kolibri-i18n + - kolibri-logging groups: babel: patterns: diff --git a/.github/workflows/i18n-download.yml b/.github/workflows/i18n-download.yml new file mode 100644 index 0000000000..09761e7255 --- /dev/null +++ b/.github/workflows/i18n-download.yml @@ -0,0 +1,87 @@ +name: Download translations from Crowdin + +on: + workflow_dispatch: + +jobs: + download: + name: Download translations and update files + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + python-version: '3.10' + activate-environment: "true" + enable-cache: "true" + + - name: Install Python dependencies + run: uv pip sync requirements.txt + + - name: Use pnpm + uses: pnpm/action-setup@v5 + + - name: Use Node.js + uses: actions/setup-node@v6 + with: + node-version: '20.x' + cache: 'pnpm' + + - name: Setup Java for crowdin-cli + uses: actions/setup-java@v5 + with: + distribution: 'temurin' + java-version: '17' + + - name: Install gettext + run: sudo apt-get update && sudo apt-get install -y gettext + + - name: Install JavaScript dependencies + run: pnpm install --frozen-lockfile + + - name: Download translations + env: + CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_API_KEY }} + run: make i18n-download + + - name: Generate App Token + id: generate-token + uses: actions/create-github-app-token@v3 + with: + app-id: ${{ secrets.LE_BOT_APP_ID }} + private-key: ${{ secrets.LE_BOT_PRIVATE_KEY }} + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v8 + with: + token: ${{ steps.generate-token.outputs.token }} + commit-message: | + Update translations from Crowdin + + This includes: + - Updated translation files (.po and .json) + - Compiled Django messages (.mo files) + - Updated frontend i18n files + branch: i18n-update-${{ github.ref_name }} + base: ${{ github.ref_name }} + delete-branch: true + title: 'Update translations from Crowdin for ${{ github.ref_name }}' + body: | + ## Summary of changes + + This PR updates translations downloaded from Crowdin. + + ### Changes included: + - Updated translation files (`.po` and `.json`) + - Compiled Django messages (`.mo` files) + - Updated frontend i18n files + + ### Testing checklist: + - [ ] Verify that translations are not obviously empty or untranslated in the message files + - [ ] Switch to a few different languages and navigate the app + labels: | + i18n + TAG: user strings diff --git a/.github/workflows/i18n-upload.yml b/.github/workflows/i18n-upload.yml new file mode 100644 index 0000000000..0e087c82c6 --- /dev/null +++ b/.github/workflows/i18n-upload.yml @@ -0,0 +1,50 @@ +name: Upload translations to Crowdin + +on: + workflow_dispatch: + +jobs: + upload: + name: Extract and upload strings to Crowdin + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + python-version: '3.10' + activate-environment: "true" + enable-cache: "true" + + - name: Install Python dependencies + run: uv pip sync requirements.txt + + - name: Use pnpm + uses: pnpm/action-setup@v5 + + - name: Use Node.js + uses: actions/setup-node@v6 + with: + node-version: '20.x' + cache: 'pnpm' + + - name: Setup Java for crowdin-cli + uses: actions/setup-java@v5 + with: + distribution: 'temurin' + java-version: '17' + + - name: Install gettext + run: sudo apt-get update && sudo apt-get install -y gettext + + - name: Install JavaScript dependencies + run: pnpm install --frozen-lockfile + + - name: Extract and upload strings to Crowdin + env: + CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_API_KEY }} + run: | + make i18n-upload + make i18n-pretranslate-approve-all diff --git a/Makefile b/Makefile index a1101b2ce4..27c222a7d2 100644 --- a/Makefile +++ b/Makefile @@ -83,29 +83,39 @@ i18n-django-compilemessages: # finds only the .po files nested there. cd contentcuration && python manage.py compilemessages +CROWDIN_BRANCH ?= unstable + i18n-upload: i18n-extract - python node_modules/kolibri-tools/lib/i18n/crowdin.py upload-sources ${branch} + pnpm exec crowdin upload sources --branch ${CROWDIN_BRANCH} i18n-pretranslate: - python node_modules/kolibri-tools/lib/i18n/crowdin.py pretranslate ${branch} + pnpm exec crowdin pre-translate --branch ${CROWDIN_BRANCH} --translate-untranslated-only --method=tm i18n-pretranslate-approve-all: - python node_modules/kolibri-tools/lib/i18n/crowdin.py pretranslate ${branch} --approve-all - -i18n-download-translations: - python node_modules/kolibri-tools/lib/i18n/crowdin.py rebuild-translations ${branch} - python node_modules/kolibri-tools/lib/i18n/crowdin.py download-translations ${branch} - pnpm exec kolibri-tools i18n-code-gen -- --output-dir ./contentcuration/contentcuration/frontend/shared/i18n + pnpm exec crowdin pre-translate --branch ${CROWDIN_BRANCH} --translate-untranslated-only --method=tm --auto-approve-option=all + +i18n-download-translations: i18n-extract-frontend + touch contentcuration/locale/.crowdin-download-marker + pnpm exec crowdin download --branch ${CROWDIN_BRANCH} + @if [ -z "$$(find contentcuration/locale/*/LC_MESSAGES -type f \( -name '*.po' -o -name '*.csv' \) -newer contentcuration/locale/.crowdin-download-marker 2>/dev/null)" ]; then \ + echo "❌ ERROR: No translation files were downloaded - Crowdin download may have failed silently"; \ + echo "Check the output above for errors during the download process"; \ + rm -f contentcuration/locale/.crowdin-download-marker; \ + exit 1; \ + fi + @echo "✅ Translation files downloaded successfully" + rm -f contentcuration/locale/.crowdin-download-marker + pnpm exec kolibri-i18n code-gen --output-dir ./contentcuration/contentcuration/frontend/shared/i18n $(MAKE) i18n-django-compilemessages - pnpm exec kolibri-tools i18n-create-message-files -- --namespace contentcuration --searchPath ./contentcuration/contentcuration/frontend + pnpm exec kolibri-i18n create-message-files --namespace contentcuration --searchPath ./contentcuration/contentcuration/frontend i18n-download: i18n-download-translations i18n-download-glossary: - python node_modules/kolibri-tools/lib/i18n/crowdin.py download-glossary + pnpm exec crowdin glossary download i18n-upload-glossary: - python node_modules/kolibri-tools/lib/i18n/crowdin.py upload-glossary + pnpm exec crowdin glossary upload ############################################################### # END I18N COMMANDS ########################################### diff --git a/babel.config.js b/babel.config.js index af49bbaa62..87772455a3 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1 +1 @@ -module.exports = require('kolibri-tools/babel.config'); +module.exports = require('kolibri-build/babel.config'); diff --git a/contentcuration/contentcuration/frontend/administration/components/sidePanels/__tests__/ReviewSubmissionSidePanel.spec.js b/contentcuration/contentcuration/frontend/administration/components/sidePanels/__tests__/ReviewSubmissionSidePanel.spec.js index e41f1095a4..5fd6089622 100644 --- a/contentcuration/contentcuration/frontend/administration/components/sidePanels/__tests__/ReviewSubmissionSidePanel.spec.js +++ b/contentcuration/contentcuration/frontend/administration/components/sidePanels/__tests__/ReviewSubmissionSidePanel.spec.js @@ -153,7 +153,7 @@ describe('ReviewSubmissionSidePanel', () => { expect(wrapper.find('[data-test="languages"]').text()).toBe('English, Czech'); expect(wrapper.find('[data-test="categories"]').text()).toBe('School, Algebra'); expect(wrapper.find('[data-test="licenses"]').text()).toBe('CC BY, CC BY-SA'); - expect(wrapper.findComponent(CommunityLibraryStatusChip).attributes('status')).toEqual( + expect(wrapper.findComponent(CommunityLibraryStatusChip).props('status')).toEqual( submission.status, ); expect(wrapper.find('[data-test="submission-notes"]').text()).toBe(submission.description); diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/sidePanels/SubmitToCommunityLibrarySidePanel/LoadingText.vue b/contentcuration/contentcuration/frontend/channelEdit/components/sidePanels/SubmitToCommunityLibrarySidePanel/LoadingText.vue index 6138ec7a0c..014aca8e54 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/sidePanels/SubmitToCommunityLibrarySidePanel/LoadingText.vue +++ b/contentcuration/contentcuration/frontend/channelEdit/components/sidePanels/SubmitToCommunityLibrarySidePanel/LoadingText.vue @@ -6,12 +6,11 @@ class="loader-wrapper" > - {{ $tr('checking') }}
-
{{ $tr('error') }}
+
{{ communityChannelsStrings.$tr('loadError') }}
@@ -20,6 +19,8 @@ - - -