Skip to content

Commit

Permalink
Merge branch 'quark-bot-discord:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
ayyneya authored Jul 2, 2024
2 parents acb8b5e + 2b8e4f3 commit 3c49364
Show file tree
Hide file tree
Showing 60 changed files with 954 additions and 120 deletions.
74 changes: 74 additions & 0 deletions .github/scripts/compare-languages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
const fs = require('fs');
const path = require('path');

function readJson(filePath) {
const rawData = fs.readFileSync(filePath, 'utf8');
return JSON.parse(rawData);
}

function getAllJsonFiles(directory) {
let jsonFiles = [];
const files = fs.readdirSync(directory);

files.forEach(file => {
const fullPath = path.join(directory, file);
if (fs.statSync(fullPath).isDirectory()) {
jsonFiles = jsonFiles.concat(getAllJsonFiles(fullPath));
} else if (file.endsWith('.json')) {
jsonFiles.push(fullPath);
}
});

return jsonFiles;
}

function compareJsonFiles(enUsDir, otherLangDir) {
const enUsFiles = getAllJsonFiles(enUsDir);
const otherLangFiles = getAllJsonFiles(otherLangDir);

const enUsFilesRelative = enUsFiles.map(file => path.relative(enUsDir, file));
const otherLangFilesRelative = otherLangFiles.map(file => path.relative(otherLangDir, file));

const missingFiles = enUsFilesRelative.filter(file => !otherLangFilesRelative.includes(file));

const missingKeys = {};

enUsFilesRelative.forEach(file => {
if (otherLangFilesRelative.includes(file)) {
const enUsJson = readJson(path.join(enUsDir, file));
const otherLangJson = readJson(path.join(otherLangDir, file));

const missingKeysInFile = Object.keys(enUsJson).filter(key => !otherLangJson.hasOwnProperty(key));
if (missingKeysInFile.length > 0) {
missingKeys[file] = missingKeysInFile;
}
}
});

return { missingFiles, missingKeys };
}

function compareAllLanguages(baseDir) {
const enUsDir = path.join(baseDir, 'en_us');
const languages = fs.readdirSync(baseDir).filter(dir => fs.statSync(path.join(baseDir, dir)).isDirectory() && dir !== 'en_us');

const report = {};

languages.forEach(lang => {
const langDir = path.join(baseDir, lang);
const { missingFiles, missingKeys } = compareJsonFiles(enUsDir, langDir);
report[lang] = { missingFiles, missingKeys };
});

return report;
}

const baseDirectory = './bot/';
const comparisonReport = compareAllLanguages(baseDirectory);

for (const [lang, report] of Object.entries(comparisonReport)) {
console.log(`Language: ${lang}`);
console.log(` Missing files: ${report.missingFiles.length > 0 ? report.missingFiles.join(', ') : 'None'}`);
console.log(` Missing keys: ${Object.keys(report.missingKeys).length > 0 ? JSON.stringify(report.missingKeys, null, 2) : 'None'}`);
console.log();
}
27 changes: 15 additions & 12 deletions .github/scripts/validate-slash_commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const conversionFile = './bot/languages.json';

let foundErrors = false;

const nonChatInputCommands = ["initialReactor.json"];

try {
const conversionData = fs.readFileSync(conversionFile, 'utf8');
const languageMap = JSON.parse(conversionData);
Expand Down Expand Up @@ -41,35 +43,36 @@ try {
const currentPath = path ? `${path}.${key}` : key;

if (typeof value === 'string') {

if (currentPath.endsWith('.description') && value.length > 100) {
console.error(`Validation error: ${directory}/${file}: Description exceeds 100 characters at '${currentPath}'`);
foundErrors = true;
}
if (currentPath.endsWith('.name') && value.includes(' ')) {
console.error(`Validation error: ${directory}/${file}: Name contains space at '${currentPath}'`);
if (currentPath.endsWith('.name') && value.match(/^[-_\p{L}\p{N}\p{sc=Deva}\p{sc=Thai}]{1,32}$/gu) == null) {
console.error(`Validation error: ${directory}/${file}: Name does not match regex at '${currentPath}', VALUE: ${value}`);
foundErrors = true;
}
if (value !== value.toLowerCase() && currentPath.endsWith('name')) {
console.error(`Validation error: ${directory}/${file}: Key '${currentPath}' must be lowercase`);
foundErrors = true;
}

} else if (typeof value === 'object' && value !== null) {
checkFields(value, currentPath);
}
});
}
if (!nonChatInputCommands.includes(file)) {
checkFields(jsonData);

checkFields(jsonData);

if (jsonData.name && jsonData.name.includes(' ')) {
console.error(`Validation error: ${directory}/${file}: Name contains space at 'name'`);
foundErrors = true;
} else if (jsonData.description && jsonData.description.length > 100) {
console.error(`Validation error: ${directory}/${file}: Description exceeds 100 characters at 'description'`);
foundErrors = true;
if (jsonData.name && jsonData.name.match(/^[-_\p{L}\p{N}\p{sc=Deva}\p{sc=Thai}]{1,32}$/gu) == null) {
console.error(`Validation error: ${directory}/${file}: Name does not match regex, VALUE: ${jsonData.name}`);
foundErrors = true;
} else if (jsonData.description && jsonData.description.length > 100) {
console.error(`Validation error: ${directory}/${file}: Description exceeds 100 characters at 'description'`);
foundErrors = true;
}
}

} catch (err) {
console.error(`Error processing ${file}:`, err);
foundErrors = true;
Expand Down
13 changes: 13 additions & 0 deletions .github/workflows/language-comparison.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
name: Language comparison

on: [workflow_dispatch]

jobs:
compare-languages:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: Compare language files
run: node .github/scripts/compare-languages.js
131 changes: 75 additions & 56 deletions activate.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,74 +3,93 @@ const path = require('path');
const fallbackLanguage = "en_us";

const baseDirectory = "bot";
const baseDirectoryActive = "active/bot";
const languages = require('./bot/languages.json');

const languagesLocation = path.join(process.cwd(), "languages", baseDirectory);
const activeLanguagesLocation = path.join(process.cwd(), "languages", "active", baseDirectory);

// relative file path is the path after the locale directory
function loadFile(locale, relativeFilePath) {

const filePath = path.join(languagesLocation, locale, relativeFilePath);

try {
let data;
if (!fs.existsSync(filePath))
data = "{}";
else
data = fs.readFileSync(filePath, 'utf8');
const jsonData = JSON.parse(data);
const fallbackLanguageData = JSON.parse(fs.readFileSync(path.join(languagesLocation, fallbackLanguage, relativeFilePath), 'utf8'));
function checkFields(obj, path = '') {
Object.keys(obj).forEach(key => {
const value = obj[key];
const currentPath = path ? `${path}.${key}` : key;

if (typeof value === 'string') {
let pointer = fallbackLanguageData;
const structPath = currentPath.split(".");
for (let i = 0; i < structPath.length - 1; i++) {
pointer = pointer[structPath[i]];
}
pointer[structPath[structPath.length - 1]] = value;
} else if (typeof value === 'object' && value !== null) {
checkFields(value, currentPath);
}
});
}

checkFields(jsonData);

const absolutePathToActiveSubdirectory = path.join(activeLanguagesLocation, locale, relativeFilePath);

if (!fs.existsSync(path.dirname(absolutePathToActiveSubdirectory)))
fs.mkdirSync(path.dirname(absolutePathToActiveSubdirectory), { recursive: true });

fs.writeFileSync(absolutePathToActiveSubdirectory, JSON.stringify(fallbackLanguageData), { recursive: true });

} catch (err) {
console.error(`Error processing ${filePath}:`, err);
foundErrors = true;
}

}

function loadSubdirectory(locale, relativePath) {
const absolutePath = path.join(languagesLocation, fallbackLanguage, relativePath);
const subdirectories = fs.readdirSync(absolutePath, { withFileTypes: true })
.filter(dirent => dirent.isDirectory())
.map(dirent => dirent.name);
const subfiles = fs.readdirSync(absolutePath, { withFileTypes: true })
.filter(dirent => !dirent.isDirectory())
.map(dirent => dirent.name);
for (let i = 0; i < subdirectories.length; i++) {
const subdirectoryPath = path.join(relativePath, subdirectories[i]);
loadSubdirectory(locale, subdirectoryPath);
}
for (let i = 0; i < subfiles.length; i++) {
const filePath = path.join(relativePath, subfiles[i]);
loadFile(locale, filePath);
}
}

function activate() {
Object.entries(languages).forEach(([key, value]) => {
const directory = path.join(process.cwd(), "languages", baseDirectory, value, "standard");

const directory = path.join(process.cwd(), "languages", baseDirectory, value);
console.log(`Processing language code ${key}...`);
if (!fs.existsSync(directory)) {
console.log(`Skipping non-existent directory: ${directory} for language code ${key}`);
return;
}

const files = fs.readdirSync(directory);
if (files.length === 0) {
console.log(`No JSON files found in ${directory}.`);
return;
}

const activeLanguageBotStandardDirectory = path.join(process.cwd(), "languages", baseDirectoryActive, value, "standard");

if (!fs.existsSync(activeLanguageBotStandardDirectory))
fs.mkdirSync(activeLanguageBotStandardDirectory, { recursive: true });

files.forEach(file => {
if (!file.endsWith('.json')) {
console.log(`Skipping non-JSON file: ${file}`);
return;
}

console.log(`Copying ${value}/${file}...`);
const filePath = path.join(directory, file);
try {
const data = fs.readFileSync(filePath, 'utf8');
const jsonData = JSON.parse(data);
const fallbackLanguageData = require(`./${baseDirectory}/${fallbackLanguage}/standard/${file}`);
function checkFields(obj, path = '') {
Object.keys(obj).forEach(key => {
const value = obj[key];
const currentPath = path ? `${path}.${key}` : key;

if (typeof value === 'string') {
let pointer = fallbackLanguageData;
const structPath = currentPath.split(".");
for (let i = 0; i < structPath.length - 1; i++) {
pointer = pointer[structPath[i]];
}
pointer[structPath[structPath.length - 1]] = value;
} else if (typeof value === 'object' && value !== null) {
checkFields(value, currentPath);
}
});
}

checkFields(jsonData);

if (!fs.existsSync(activeLanguageBotStandardDirectory))
fs.mkdirSync(activeLanguageBotStandardDirectory, { recursive: true });

fs.writeFileSync(path.join(activeLanguageBotStandardDirectory, file), JSON.stringify(fallbackLanguageData));
if (!fs.existsSync(activeLanguagesLocation))
fs.mkdirSync(activeLanguagesLocation, { recursive: true });

} catch (err) {
console.error(`Error processing ${file}:`, err);
foundErrors = true;
}
});
console.log(`Copying ${directory}...`);
loadSubdirectory(value, "/");

});

}

module.exports = activate;
module.exports = activate;
4 changes: 4 additions & 0 deletions bot/en_gb/access_token.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"1": "Admin",
"2": "Basic"
}
3 changes: 3 additions & 0 deletions bot/en_gb/channel_update_types.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"none": "none"
}
19 changes: 16 additions & 3 deletions bot/en_gb/command_responses.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@
"response-unban": "Unbanned",
"response-purge": "Purged {count} messages",

"response-customise-dash": "Customisation settings have moved to our [web dashboard]!",
"response-customise-1": "Log messages up to 2 weeks old, customise logs, and so much more with Quark Pro...",
"response-customise-dash": "Customisation settings have moved to Quark's [web dashboard]!",
"response-customise-1": "Log messages up to 8 weeks old, customise logs, and so much more with Quark Pro...",
"response-customise-2": "[UK, US, EU] Click onto my profile to upgrade!",
"response-customise-3": "Or... {proLink}",
"response-customise-3": "See subscriptions... {proLink}",
"response-customise-4": "Try out colour customisation for free at {inventoryLink}",

"response-case-updated": "Case updated!",
Expand Down Expand Up @@ -104,11 +104,17 @@
"setserverlog-type-channels-1": "channel events",
"setserverlog-type-modlogs-0": "Modlogs",
"setserverlog-type-modlogs-1": "modlogs",
"setserverlog-type-quark-0": "Quark Events",
"setserverlog-type-quark-1": "quark events",
"setserverlog-spoilers": "Spoilers",
"setserverlog-spoilers-0": "Serverlog spoilers set to {result}",
"setserverlog-enable-status-updates": "Enable Status Updates!",
"setserverlog-enable-status-updates-desc": "Get notified of all the latest updates, downtime, and other important communications from the developers!",
"setserverlog-enable-status-updates-desc-1": "We highly recommend you enable this in one of your channels!",
"setserverlog-check-permissions": "Please ensure Quark has permission to send messages in this channel, or the channel will be unset.",

"festive-title": "Free Festive Gift!",
"festive-claim": "Claim your free gift!",

"help-overview-website-description": "Easily set up and manage Quark from the [web dashboard]!",
"help-overview-inventory-description": "Manage your subscriptions or get some [Quark Pro] features for free!",
Expand Down Expand Up @@ -154,6 +160,9 @@
"need-to-vote": "Click here to vote",
"need-to-vote-footer": "Votes take up to a minute to be registered",

"initialreactors-expired": "expired",
"initialreactors-notfound": "No reactions found",

"configCommand": {
"title": "Serverlog Configuration",
"selection": "Select a category in the menu to view configuration.",
Expand Down Expand Up @@ -202,6 +211,10 @@
"title": "Overview",
"description": "Overview of main category options"
},
"quarkEvents": {
"title": "Quark Config",
"description": "Changes made to Quark's configuration for this server"
},
"fileEvents": {
"title": "Files"
}
Expand Down
3 changes: 3 additions & 0 deletions bot/en_gb/emoji_update_types.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"none": "none"
}
4 changes: 4 additions & 0 deletions bot/en_gb/gui_constants.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,9 @@
"explicit_content_filter": "Explicit Content Filter",
"nsfw_level": "NSFW Level",
"premium_progress_bar_enabled": "Progress Bar"
},
"webhookModificationTypes": {
"name": "Name",
"channel_id": "Channel"
}
}
12 changes: 12 additions & 0 deletions bot/en_gb/ignore_options.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"ignoreTargets": "Ignore Target Users",
"ignoreExecutors": "Ignore Target Executors",
"specificMessageContent": "Ignore Specific Message Content",
"ignoreChannels": "Ignore Channels",
"ignoreBotExecutors": "Ignore Bot Executors",
"ignoreBotTargets": "Ignore Bot Targets",
"ignoreExecutorRoles": "Ignore Executor Roles",
"ignoreTargetRoles": "Ignore Target Roles",
"ignoreCategories": "Ignore Categories",
"activeIgnore": "Active Ignore"
}
Loading

0 comments on commit 3c49364

Please sign in to comment.