Files
podkop/fe-app-podkop/generate-po.js
2025-10-21 21:33:51 +03:00

114 lines
3.6 KiB
JavaScript

import fs from 'fs/promises';
import { execSync } from 'child_process';
const lang = process.argv[2];
if (!lang) {
console.error('❌ Укажи язык, например: node generate-po.js ru');
process.exit(1);
}
const callsPath = 'locales/calls.json';
const poPath = `locales/podkop.${lang}.po`;
function getGitUser() {
try {
return execSync('git config user.name').toString().trim();
} catch {
return 'Automatically generated';
}
}
function getHeader(lang) {
const now = new Date();
const date = now.toISOString().split('T')[0];
const time = now.toTimeString().split(' ')[0].slice(0, 5);
const tzOffset = (() => {
const offset = -now.getTimezoneOffset();
const sign = offset >= 0 ? '+' : '-';
const hours = String(Math.floor(Math.abs(offset) / 60)).padStart(2, '0');
const minutes = String(Math.abs(offset) % 60).padStart(2, '0');
return `${sign}${hours}${minutes}`;
})();
const translator = getGitUser();
const pluralForms = lang === 'ru'
? 'nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);'
: 'nplurals=2; plural=(n != 1);';
return [
`# ${lang.toUpperCase()} translations for PODKOP package.`,
`# Copyright (C) ${now.getFullYear()} THE PODKOP'S COPYRIGHT HOLDER`,
`# This file is distributed under the same license as the PODKOP package.`,
`# ${translator}, ${now.getFullYear()}.`,
'#',
'msgid ""',
'msgstr ""',
`"Project-Id-Version: PODKOP\\n"`,
`"Report-Msgid-Bugs-To: \\n"`,
`"POT-Creation-Date: ${date} ${time}${tzOffset}\\n"`,
`"PO-Revision-Date: ${date} ${time}${tzOffset}\\n"`,
`"Last-Translator: ${translator}\\n"`,
`"Language-Team: none\\n"`,
`"Language: ${lang}\\n"`,
`"MIME-Version: 1.0\\n"`,
`"Content-Type: text/plain; charset=UTF-8\\n"`,
`"Content-Transfer-Encoding: 8bit\\n"`,
`"Plural-Forms: ${pluralForms}\\n"`,
'',
];
}
function parsePo(content) {
const lines = content.split('\n');
const translations = new Map();
let msgid = null;
let msgstr = null;
for (const line of lines) {
if (line.startsWith('msgid ')) {
msgid = JSON.parse(line.slice(6));
} else if (line.startsWith('msgstr ') && msgid !== null) {
msgstr = JSON.parse(line.slice(7));
translations.set(msgid, msgstr);
msgid = null;
msgstr = null;
}
}
return translations;
}
function escapePoString(str) {
return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
}
async function generatePo() {
const [callsRaw, oldPoRaw] = await Promise.all([
fs.readFile(callsPath, 'utf8'),
fs.readFile(poPath, 'utf8').catch(() => ''),
]);
const calls = JSON.parse(callsRaw);
const oldTranslations = parsePo(oldPoRaw);
const header = getHeader(lang);
const body = calls
.map(({ key }) => {
const msgid = key;
const msgstr = oldTranslations.get(msgid) || '';
return [
`msgid "${escapePoString(msgid)}"`,
`msgstr "${escapePoString(msgstr)}"`,
''
].join('\n');
})
.join('\n');
const finalPo = header.join('\n') + '\n' + body;
await fs.writeFile(poPath, finalPo, 'utf8');
console.log(`✅ Файл ${poPath} успешно сгенерирован. Переведено ${[...oldTranslations.keys()].length}/${calls.length}`);
}
generatePo().catch((err) => {
console.error('Ошибка генерации PO файла:', err);
});