fix(ci): correctly update translations from crowdin
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
54
.github/workflows/crowdin.yml
vendored
54
.github/workflows/crowdin.yml
vendored
@ -11,20 +11,48 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: crowdin action
|
||||
- name: push source files
|
||||
uses: crowdin/github-action@v2
|
||||
with:
|
||||
crowdin_branch_name: main
|
||||
dryrun_action: true
|
||||
upload_sources: true
|
||||
download_translations: true
|
||||
export_only_approved: true
|
||||
push_translations: true
|
||||
localization_branch_name: main
|
||||
create_pull_request: false
|
||||
commit_message: 'chore(i18n): update translations via Crowdin'
|
||||
command: 'push'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.CROWDIN_GH_TOKEN }}
|
||||
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
|
||||
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
||||
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
||||
- name: pull translations
|
||||
uses: crowdin/github-action@v2
|
||||
with:
|
||||
command: 'download'
|
||||
command_args: '--export-only-approved --skip-untranslated-strings'
|
||||
env:
|
||||
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
|
||||
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
- name: Ensure file permissions
|
||||
run: |
|
||||
find pkg/i18n/lang frontend/src/i18n/lang -type f -name "*.json" -exec sudo chmod 666 {} \;
|
||||
- name: Fix exported files
|
||||
run: |
|
||||
node contrib/clean-translations.js
|
||||
- name: Check for changes
|
||||
id: check_changes
|
||||
run: |
|
||||
if git diff --quiet; then
|
||||
echo "changes_exist=0" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "changes_exist=1" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
- name: Commit files
|
||||
if: steps.check_changes.outputs.changes_exist != '0'
|
||||
run: |
|
||||
git config --local user.email "frederik@vikunja.io"
|
||||
git config --local user.name "Frederick [Bot]"
|
||||
git commit -am "chore(i18n): update translations via Crowdin"
|
||||
- name: Push changes
|
||||
if: steps.check_changes.outputs.changes_exist != '0'
|
||||
uses: ad-m/github-push-action@master
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branch: ${{ github.ref }}
|
||||
|
7
.github/workflows/release.yml
vendored
7
.github/workflows/release.yml
vendored
@ -296,8 +296,11 @@ jobs:
|
||||
- name: Check for changes
|
||||
id: check_changes
|
||||
run: |
|
||||
git diff --quiet
|
||||
echo "changes_exist=$?" >> "$GITHUB_OUTPUT"
|
||||
if git diff --quiet; then
|
||||
echo "changes_exist=0" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "changes_exist=1" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
- name: Commit files
|
||||
if: steps.check_changes.outputs.changes_exist != '0'
|
||||
run: |
|
||||
|
124
contrib/clean-translations.js
Executable file
124
contrib/clean-translations.js
Executable file
@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Script to remove empty JSON keys from translation files
|
||||
*
|
||||
* This script traverses through the specified directories and removes all
|
||||
* empty string values from JSON files recursively.
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
// Get the root directory (where the script is run from)
|
||||
const rootDir = process.cwd();
|
||||
|
||||
// Define directories to process (relative to root)
|
||||
const directories = [
|
||||
path.join(rootDir, 'pkg/i18n/lang'),
|
||||
path.join(rootDir, 'frontend/src/i18n/lang')
|
||||
];
|
||||
|
||||
/**
|
||||
* Recursively removes empty string values from an object
|
||||
* @param {Object} obj - The object to clean
|
||||
* @returns {Object} - The cleaned object with empty strings removed
|
||||
*/
|
||||
function removeEmptyStrings(obj) {
|
||||
if (typeof obj !== 'object' || obj === null) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Handle arrays
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map(item => removeEmptyStrings(item))
|
||||
.filter(item => item !== '');
|
||||
}
|
||||
|
||||
// Handle objects
|
||||
const result = {};
|
||||
|
||||
for (const key in obj) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
const value = obj[key];
|
||||
|
||||
if (value === '') {
|
||||
// Skip empty strings
|
||||
continue;
|
||||
} else if (typeof value === 'object' && value !== null) {
|
||||
// Recursively clean nested objects
|
||||
const cleanedValue = removeEmptyStrings(value);
|
||||
|
||||
// Only add non-empty objects
|
||||
if (typeof cleanedValue === 'object' &&
|
||||
!Array.isArray(cleanedValue) &&
|
||||
Object.keys(cleanedValue).length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result[key] = cleanedValue;
|
||||
} else {
|
||||
// Keep non-empty values
|
||||
result[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a single JSON file to remove empty strings
|
||||
* @param {string} filePath - Path to the JSON file
|
||||
*/
|
||||
function processFile(filePath) {
|
||||
try {
|
||||
console.log(`Processing ${filePath}`);
|
||||
|
||||
// Read and parse the JSON file
|
||||
const data = fs.readFileSync(filePath, 'utf8');
|
||||
const json = JSON.parse(data);
|
||||
|
||||
// Clean the JSON data
|
||||
const cleanedJson = removeEmptyStrings(json);
|
||||
|
||||
// Write the cleaned JSON back to the file
|
||||
fs.writeFileSync(
|
||||
filePath,
|
||||
JSON.stringify(cleanedJson, null, '\t'),
|
||||
'utf8'
|
||||
);
|
||||
|
||||
console.log(`Successfully cleaned ${filePath}`);
|
||||
} catch (error) {
|
||||
console.error(`Error processing ${filePath}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process all JSON files in the specified directories
|
||||
*/
|
||||
function main() {
|
||||
directories.forEach(dir => {
|
||||
if (!fs.existsSync(dir)) {
|
||||
console.warn(`Directory ${dir} does not exist. Skipping.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const files = fs.readdirSync(dir);
|
||||
|
||||
files.forEach(file => {
|
||||
const filePath = path.join(dir, file);
|
||||
|
||||
if (file.endsWith('.json') && file !== 'en.json') {
|
||||
processFile(filePath);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
console.log('All translation files have been processed successfully!');
|
||||
}
|
||||
|
||||
// Run the script
|
||||
main();
|
Reference in New Issue
Block a user