diff --git a/.github/workflows/extract-translations.yml b/.github/workflows/extract-translations.yml new file mode 100644 index 000000000..7b50e6937 --- /dev/null +++ b/.github/workflows/extract-translations.yml @@ -0,0 +1,47 @@ +# GitHub Action to extract translations and (later) upload them to Crowdin. + +name: Extract translations +on: + # Execute for all commits (to ensure translations extraction works) + push: + # Allows to run this workflow manually from the Actions tab. + workflow_dispatch: + +jobs: + extract-translations: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + # Cache npm dependencies to speed up the workflow + - name: Cache node modules + uses: actions/cache@v2 + env: + cache-name: cache-newIDE-app-node_modules + with: + # npm cache files are stored in `~/.npm` on Linux/macOS + path: ~/.npm + key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('newIDE/app/package-lock.json') }} + + - name: Install gettext + run: sudo apt update && sudo apt install gettext -y + + - name: Install newIDE dependencies + run: npm install + working-directory: newIDE/app + + - name: Extract translations + run: npm run extract-all-translations + working-directory: newIDE/app + + # Only upload on Crowdin for the master branch + - name: Install Crowdin CLI + if: github.ref == 'refs/heads/master' + run: npm i -g @crowdin/cli + + - name: Upload translations to Crowdin + run: crowdin upload sources + if: github.ref == 'refs/heads/master' + env: + CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} + CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 000000000..145691a7a --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,22 @@ +'project_id_env': 'CROWDIN_PROJECT_ID' +'api_token_env': 'CROWDIN_PERSONAL_TOKEN' +'base_path': '.' +'base_url': 'https://api.crowdin.com' + +# Flatten files in Crowdin +'preserve_hierarchy': false + +# "Source" files, which are .POT files extracted from the source code. +# The built files are .PO files that are the compiled by `compile-translations` +# script in `newIDE/app/scripts`. +files: + [ + { + 'source': 'newIDE/app/src/locales/en/ide-messages.pot', + 'translation': 'newIDE/app/src/locales/%locale_with_underscore%/ide-messages.po', + }, + { + 'source': 'scripts/gdcore-gdcpp-gdjs-extensions-messages.pot', + 'translation': 'newIDE/app/src/locales/%locale_with_underscore%/gdcore-gdcpp-gdjs-extensions-messages.po', + }, + ] diff --git a/newIDE/app/package-lock.json b/newIDE/app/package-lock.json index d2b3ae6c9..e654905aa 100644 --- a/newIDE/app/package-lock.json +++ b/newIDE/app/package-lock.json @@ -15015,6 +15015,12 @@ } } }, + "babel-core": { + "version": "7.0.0-bridge.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", + "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", + "dev": true + }, "babel-eslint": { "version": "10.0.3", "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.3.tgz", diff --git a/newIDE/app/package.json b/newIDE/app/package.json index b60236149..25bd25995 100644 --- a/newIDE/app/package.json +++ b/newIDE/app/package.json @@ -10,6 +10,7 @@ "@storybook/addon-essentials": "6.3.8", "@storybook/react": "6.3.8", "axios-mock-adapter": "^1.19.0", + "babel-core": "^7.0.0-bridge.0", "babel-loader": "8.0.6", "flow-bin": "0.131.0", "flow-coverage-report": "^0.4.0", diff --git a/newIDE/app/package.json.README.md b/newIDE/app/package.json.README.md index a234573a9..25d48d46e 100644 --- a/newIDE/app/package.json.README.md +++ b/newIDE/app/package.json.README.md @@ -10,6 +10,8 @@ GDevelop relies on some dependencies that can have special requirements: - `babel-loader` is specified to be the exact version required by `react-scripts` (because `react-scripts` wants the exact version and will complain if forced to use the `babel-loader` of Storybook). - **Try removing these extra `devDependencies`** if you upgrade Storybook or Create React App. +- `"babel-core": "^7.0.0-bridge.0"` is needed for js-lingui `lingui extract` command (who runs Babel on source files). + - **`react-dnd`** is used by `react-mosaic-component` and `react-sortable-tree` (but not `react-sortable-hoc`). Both must be using **the same versions** of `react-dnd` and `react-dnd-html5-backend`. Otherwise, you get blanks/not rendered components. > You can check if there is only one version of a package by doing `npm ls` or `yarn why`: diff --git a/newIDE/app/scripts/extract-all-translations.js b/newIDE/app/scripts/extract-all-translations.js index 7d6964807..9c5adace9 100644 --- a/newIDE/app/scripts/extract-all-translations.js +++ b/newIDE/app/scripts/extract-all-translations.js @@ -12,24 +12,29 @@ let hasErrors = false; // Clean existing English messages catalog, if any const enMessagesJsPath = path.join(newIdeAppPath, 'src/locales/en/messages.js'); if (fs.existsSync(enMessagesJsPath)) { - shell.echo(`ℹ️ Removing ${enMessagesJsPath} as "en" should not have any translations ("pot" file)`); + shell.echo( + `ℹ️ Removing ${enMessagesJsPath} as "en" should not have any translations ("pot" file)` + ); shell.rm(enMessagesJsPath); } -const enIdeMessagesPotPath = path.join(newIdeAppPath, 'src/locales/en/ide-messages.pot'); +const enIdeMessagesPotPath = path.join( + newIdeAppPath, + 'src/locales/en/ide-messages.pot' +); if (fs.existsSync(enIdeMessagesPotPath)) { - shell.echo(`ℹ️ Removing ${enIdeMessagesPotPath} as "en" should not have any translations ("pot" file)`); + shell.echo( + `ℹ️ Removing ${enIdeMessagesPotPath} as "en" should not have any translations ("pot" file)` + ); shell.rm(enIdeMessagesPotPath); } // Launch "lingui extract" for extracting newIDE translations shell.echo('ℹ️ Extracting translations for newIDE...'); -hasErrors |= shell.exec( - 'node node_modules/.bin/lingui extract --clean --overwrite', - { +hasErrors |= + shell.exec('node node_modules/.bin/lingui extract --clean --overwrite', { cwd: newIdeAppPath, - } -).stderr; + }).code !== 0; shell.echo('ℹ️ Renaming extracted translations to ide-messages.po...'); getLocales().then(locales => @@ -53,17 +58,20 @@ shell.echo( 'ℹ️ Extracting translations for GDCore/GDJS/Extensions to scripts/gdcore-gdcpp-gdjs-extensions-messages.pot...' ); if (isWin) { - hasErrors |= shell.exec('ExtractTranslations.bat', { - cwd: gdScriptsPath, - }).stderr; + hasErrors |= + shell.exec('ExtractTranslations.bat', { + cwd: gdScriptsPath, + }).code !== 0; } else { - hasErrors |= shell.exec('./ExtractTranslations.sh ', { - cwd: gdScriptsPath, - }).stderr; + hasErrors |= + shell.exec('./ExtractTranslations.sh ', { + cwd: gdScriptsPath, + }).code !== 0; } if (!hasErrors) { shell.echo('✅ Translations extracted'); } else { shell.echo(`❌ Error(s) occurred while extracting translations`); + shell.exit(1); } diff --git a/newIDE/app/yarn.lock b/newIDE/app/yarn.lock index 9e8c17ca5..5151f0ba7 100644 --- a/newIDE/app/yarn.lock +++ b/newIDE/app/yarn.lock @@ -4677,6 +4677,11 @@ babel-code-frame@^6.22.0: esutils "^2.0.2" js-tokens "^3.0.2" +babel-core@^7.0.0-bridge.0: + version "7.0.0-bridge.0" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece" + integrity sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg== + babel-eslint@10.0.3: version "10.0.3" resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.3.tgz#81a2c669be0f205e19462fed2482d33e4687a88a" diff --git a/scripts/ExtractTranslations.sh b/scripts/ExtractTranslations.sh index 45dc6866c..95ba6c35e 100755 --- a/scripts/ExtractTranslations.sh +++ b/scripts/ExtractTranslations.sh @@ -1,5 +1,7 @@ #Launch this script to generate the .POT file used #to update the strings to be translated. +set -e + echo "ℹ️ Listing all GDCore, GDJS and Extensions sources files to translate..." find ../GDJS/GDJS/ -name '*.cpp' | grep -v '/Dialogs/' > /tmp/listfile.txt @@ -22,4 +24,5 @@ if type $GETTEXT 2>/dev/null; then echo "ℹ️ Translation file 'gdcore-gdcpp-gdjs-extensions-messages.pot' generated and ready to be sent to Crowdin or used in a translation software like PoEdit." else echo "❌ Unable to find xgettext on your system." + exit 1 fi