Skip to content

p5.js Reference Translation Automation Task #863

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
228 changes: 228 additions & 0 deletions .github/actions/translation-tracker/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');


const SUPPORTED_LANGUAGES = ['es', 'hi', 'ko', 'zh-Hans'];
const REFERENCE_PATH = 'src/content/reference';
const ENGLISH_PATH = path.join(REFERENCE_PATH, 'en');


function getChangedFiles() {
try {



const gitCommand = process.env.GITHUB_EVENT_NAME === 'pull_request'
? 'git diff --name-only HEAD~1 HEAD'
: 'git diff --name-only HEAD~1 HEAD';

const changedFilesOutput = execSync(gitCommand, { encoding: 'utf8' });
const allChangedFiles = changedFilesOutput.trim().split('\n').filter(file => file.length > 0);


const changedEnglishFiles = allChangedFiles.filter(file =>
file.startsWith(ENGLISH_PATH) && file.endsWith('.mdx')
);

console.log(` Total changed files: ${allChangedFiles.length}`);
console.log(` Changed English reference files: ${changedEnglishFiles.length}`);

if (changedEnglishFiles.length > 0) {
console.log('📄 Changed English files:');
changedEnglishFiles.forEach(file => console.log(` - ${file}`));
}

return changedEnglishFiles;
} catch (error) {
console.error(' Error getting changed files:', error.message);
return [];
}
}


function getTranslationPath(englishFilePath, language) {
return englishFilePath.replace('/en/', `/${language}/`);
}

/**
* Check if a file exists
*/
function fileExists(filePath) {
try {
return fs.existsSync(filePath);
} catch (error) {
return false;
}
}


function getFileModTime(filePath) {
try {
return fs.statSync(filePath).mtime;
} catch (error) {
return null;
}
}


function checkTranslationStatus(changedEnglishFiles) {


const translationStatus = {
needsUpdate: [],
missing: [],
upToDate: []
};

changedEnglishFiles.forEach(englishFile => {


const englishModTime = getFileModTime(englishFile);
if (!englishModTime) {
console.log(`Could not get modification time for English file`);
return;
}

SUPPORTED_LANGUAGES.forEach(language => {
const translationPath = getTranslationPath(englishFile, language);
const exists = fileExists(translationPath);

if (!exists) {
console.log(` ❌ ${language}: Missing translation`);
translationStatus.missing.push({
englishFile,
language,
translationPath,
status: 'missing'
});
} else {
const translationModTime = getFileModTime(translationPath);
const isOutdated = translationModTime < englishModTime;

if (isOutdated) {
console.log(` 🔄 ${language}: Needs update (English: ${englishModTime.toISOString()}, Translation: ${translationModTime.toISOString()})`);
translationStatus.needsUpdate.push({
englishFile,
language,
translationPath,
status: 'outdated',
englishModTime,
translationModTime
});
} else {
console.log(` ✅ ${language}: Up to date`);
translationStatus.upToDate.push({
englishFile,
language,
translationPath,
status: 'up-to-date'
});
}
}
});
});

return translationStatus;
}


function displaySummary(translationStatus) {
console.log('\n📊 TRANSLATION STATUS SUMMARY');
console.log('═══════════════════════════════');

console.log(`🆕 Missing translations: ${translationStatus.missing.length}`);
if (translationStatus.missing.length > 0) {
translationStatus.missing.forEach(item => {
console.log(` - ${item.language}: ${item.englishFile}`);
});
}

console.log(`🔄 Outdated translations: ${translationStatus.needsUpdate.length}`);
if (translationStatus.needsUpdate.length > 0) {
translationStatus.needsUpdate.forEach(item => {
console.log(` - ${item.language}: ${item.englishFile}`);
});
}

console.log(`✅ Up-to-date translations: ${translationStatus.upToDate.length}`);

console.log('\n💡 Next steps for Week 2+:');


function exploreRepoStructure() {
console.log('\n🔍 REPOSITORY STRUCTURE ANALYSIS');
console.log('═══════════════════════════════════');

try {
const referencePath = REFERENCE_PATH;
console.log(`📁 Reference path: ${referencePath}`);

if (fs.existsSync(referencePath)) {
const languages = fs.readdirSync(referencePath)
.filter(item => fs.statSync(path.join(referencePath, item)).isDirectory())
.filter(item => !item.startsWith('.'));

console.log(`🌐 Available languages: ${languages.join(', ')}`);

// Count files in each language
languages.forEach(lang => {
const langPath = path.join(referencePath, lang);
try {
const subdirs = fs.readdirSync(langPath)
.filter(item => fs.statSync(path.join(langPath, item)).isDirectory());

let totalFiles = 0;
subdirs.forEach(subdir => {
const subdirPath = path.join(langPath, subdir);
const files = fs.readdirSync(subdirPath)
.filter(file => file.endsWith('.mdx'));
totalFiles += files.length;
});

console.log(` ${lang}: ${totalFiles} files across ${subdirs.length} categories`);
} catch (error) {
console.log(` ${lang}: Error reading directory - ${error.message}`);
}
});
} else {
console.log(` Reference path does not exist: ${referencePath}`);
}
} catch (error) {
console.error(' Error exploring repository structure:', error.message);
}
}


function main() {
console.log('p5.js Translation Sync Tracker - Week 1 Prototype');
console.log('════════════════════════════════════════════════════');
console.log(`📅 Event: ${process.env.GITHUB_EVENT_NAME || 'local'}`);
console.log(`🏠 Working directory: ${process.cwd()}`);
console.log(`🎯 Tracking languages: ${SUPPORTED_LANGUAGES.join(', ')}`);


exploreRepoStructure();


const changedEnglishFiles = getChangedFiles();

if (changedEnglishFiles.length === 0) {
console.log(' No changes detected in English reference files.');
console.log(' Nothing to track for translations in this commit!');
return;
}


const translationStatus = checkTranslationStatus(changedEnglishFiles);


displaySummary(translationStatus);


}

// Run the main function
if (require.main === module) {
main();
}
26 changes: 26 additions & 0 deletions .github/actions/translation-tracker/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "p5js-translation-tracker",
"version": "1.0.0",
"description": "GitHub Action to track translation status for p5.js reference documentation",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "node index.js"
},
"keywords": [
"p5.js",
"translation",
"documentation",
"github-actions",
"automation"
],
"author": "Divyansh Srivastava",
"license": "LGPL-2.1",
"engines": {
"node": ">=18.0.0"
},
"dependencies": {
"@actions/core": "^1.10.0",
"@actions/github": "^5.1.1"
}
}
39 changes: 39 additions & 0 deletions .github/actions/translation-tracker/test-local.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env node

/**
* Local test script for the translation tracker
* This simulates the GitHub Action environment for testing
*/

const { execSync } = require('child_process');
const path = require('path');

process.env.GITHUB_EVENT_NAME = 'push';
process.env.GITHUB_WORKSPACE = process.cwd();

console.log('🧪 LOCAL TEST: Translation Tracker');
console.log('═══════════════════════════════════');
console.log(`📁 Working directory: ${process.cwd()}`);

// Navigate to repository root
const repoRoot = path.resolve(__dirname, '../../..');
process.chdir(repoRoot);

console.log(`📁 Changed to repository root: ${process.cwd()}`);

try {
const gitLogOutput = execSync('git log --oneline -5', { encoding: 'utf8' });
console.log(' Recent commits:');
console.log(gitLogOutput);
} catch (error) {
console.log(' No git history available or not in a git repository');
}

console.log(' Running translation tracker...\n');

try {
require('./index.js');
} catch (error) {
console.error('❌ Error running translation tracker:', error.message);
console.error(error.stack);
}
34 changes: 34 additions & 0 deletions .github/workflows/translation-sync.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Translation Sync Tracker

on:
push:
branches: [main]
paths:
- 'src/content/reference/en/**'
pull_request:
branches: [main]
paths:
- 'src/content/reference/en/**'

jobs:
track-translation-changes:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 2 # Fetch previous commit to compare changes

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'

- name: Install dependencies
run: npm ci

- name: Run translation tracker
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: node .github/actions/translation-tracker/index.js
2 changes: 2 additions & 0 deletions src/content/reference/en/p5/accelerationX.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ description: >

device along the x axis. Value is represented as meters per second
squared.</p>

<p>Test modification to demonstrate missing translation detection.</p>
line: 23
isConstructor: false
itemtype: property
Expand Down
2 changes: 2 additions & 0 deletions src/content/reference/en/p5/circle.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ file: src/core/shape/2d_primitives.js
description: >
<p>Draws a circle.</p>

<p>This is a test modification for the translation tracker.</p>

<p>A circle is a round shape defined by the <code>x</code>, <code>y</code>,
and <code>d</code> parameters.

Expand Down
2 changes: 2 additions & 0 deletions src/content/reference/en/p5/triangle.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ file: src/core/shape/2d_primitives.js
description: >
<p>Draws a triangle.</p>

<p>Test modification for translation tracker testing.</p>

<p>A triangle is a three-sided shape defined by three points. The

first two parameters specify the triangle's first point <code>(x1, y1)</code>.
Expand Down
Loading