mirror of
https://github.com/itdoginfo/podkop.git
synced 2025-12-06 11:36:50 +03:00
feat: implement locales scripts
This commit is contained in:
113
fe-app-podkop/generate-po.js
Normal file
113
fe-app-podkop/generate-po.js
Normal file
@@ -0,0 +1,113 @@
|
||||
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);
|
||||
});
|
||||
Reference in New Issue
Block a user