项目文件夹

文件
2026-07-13 12:22:50 +08:00

166 行
4.2 KiB
JavaScript

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
#!/usr/bin/env node
/**
* Sync translations with Weblate
*/
const axios = require('axios');
const fs = require('fs');
const path = require('path');
const WEBLATE_API_URL =
process.env.WEBLATE_API_URL || 'https://hosted.weblate.org/api';
const WEBLATE_TOKEN = process.env.WEBLATE_TOKEN;
const PROJECT_SLUG = process.env.WEBLATE_PROJECT || 'pocketpal-ai';
const COMPONENT_SLUG = process.env.WEBLATE_COMPONENT || 'translations';
if (!WEBLATE_TOKEN) {
console.log('️ WEBLATE_TOKEN not set, skipping Weblate sync');
process.exit(0);
}
async function uploadSourceFile() {
const enPath = path.join(__dirname, '../src/locales/en.json');
if (!fs.existsSync(enPath)) {
console.error('Source file en.json not found');
process.exit(1);
}
try {
const fileContent = fs.readFileSync(enPath);
const formData = new FormData();
formData.append('file', new Blob([fileContent]), 'en.json');
formData.append('method', 'replace');
const response = await axios.post(
`${WEBLATE_API_URL}/translations/${PROJECT_SLUG}/${COMPONENT_SLUG}/en/file/`,
formData,
{
headers: {
Authorization: `Token ${WEBLATE_TOKEN}`,
},
},
);
console.log('Uploaded source file to Weblate:', response.status);
} catch (error) {
console.error(
'Failed to upload source file:',
error.response?.data || error.message,
);
}
}
async function downloadTranslations() {
const languages = [
'fa',
'he',
'id',
'ja',
'ko',
'ms',
'pt_BR',
'ru',
'uk',
'zh',
'zh_Hant',
];
for (const lang of languages) {
try {
const response = await axios.get(
`${WEBLATE_API_URL}/translations/${PROJECT_SLUG}/${COMPONENT_SLUG}/${lang}/file/`,
{
headers: {
Authorization: `Token ${WEBLATE_TOKEN}`,
},
},
);
const filePath = path.join(__dirname, `../src/locales/${lang}.json`);
fs.writeFileSync(filePath, JSON.stringify(response.data, null, 2));
console.log(`✅ Downloaded ${lang}.json`);
} catch (error) {
if (error.response?.status === 404) {
console.log(
`️ Translation for ${lang} not found in Weblate, keeping local version`,
);
} else {
console.error(
`❌ Failed to download ${lang}.json:`,
error.response?.data || error.message,
);
}
}
}
}
async function getProjectStats() {
try {
const response = await axios.get(
`${WEBLATE_API_URL}/projects/${PROJECT_SLUG}/statistics/`,
{
headers: {
Authorization: `Token ${WEBLATE_TOKEN}`,
},
},
);
console.log('\n📊 Translation Statistics:');
console.log(`Total strings: ${response.data.total}`);
console.log(
`Translated: ${response.data.translated} (${response.data.translated_percent}%)`,
);
console.log(`Needs editing: ${response.data.fuzzy}`);
console.log(`Failing checks: ${response.data.failing_checks}`);
} catch (error) {
console.error(
'❌ Failed to get project stats:',
error.response?.data || error.message,
);
}
}
async function main() {
const command = process.argv[2];
switch (command) {
case 'upload':
await uploadSourceFile();
break;
case 'download':
await downloadTranslations();
break;
case 'sync':
await uploadSourceFile();
await downloadTranslations();
break;
case 'stats':
await getProjectStats();
break;
default:
console.log(`
Usage: node scripts/sync-weblate.js <command>
Commands:
upload Upload source file (en.json) to Weblate
download Download translated files from Weblate
sync Upload source and download translations
stats Show translation statistics
Environment variables:
WEBLATE_TOKEN - Your Weblate API token (required)
WEBLATE_API_URL - Weblate API URL (default: https://hosted.weblate.org/api)
WEBLATE_PROJECT - Project slug (default: pocketpal-ai)
WEBLATE_COMPONENT - Component slug (default: translations)
`);
process.exit(1);
}
}
main().catch(error => {
console.error('❌ Script failed:', error);
process.exit(1);
});