2023-01-17 22:29:15 +01:00
|
|
|
import { Client } from "discord.js";
|
|
|
|
import { readdir } from "fs/promises";
|
|
|
|
import { removeExtension } from "./misc";
|
2022-07-22 11:46:47 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Load the localizations files into memory.
|
|
|
|
*
|
|
|
|
* Show percentage of translations.
|
|
|
|
* @param default_lang default lang
|
|
|
|
* @returns Map of map with all the localizations
|
|
|
|
*/
|
|
|
|
export const loadLocales = async (default_lang: string) => {
|
2023-01-17 22:29:15 +01:00
|
|
|
// Get files from locales/ directory
|
|
|
|
const old_path = __dirname.split("/");
|
|
|
|
old_path.pop();
|
|
|
|
const files = await readdir(`${old_path.join("/")}/locales`);
|
|
|
|
|
|
|
|
// Read JSON files content and load it into the memory
|
|
|
|
const locales = new Map<string, Map<string, string>>();
|
|
|
|
await Promise.all(
|
|
|
|
files.map(async (lang) => {
|
|
|
|
// Import file
|
|
|
|
const content: {
|
|
|
|
[key: string]: string;
|
|
|
|
} = await import(`../locales/${lang}`);
|
|
|
|
|
|
|
|
// Add it to the memory
|
|
|
|
locales.set(
|
|
|
|
removeExtension(lang),
|
|
|
|
new Map(
|
|
|
|
Object.keys(content)
|
|
|
|
// Ignore the default key
|
|
|
|
.filter((str) => str !== "default")
|
|
|
|
.map((str) => {
|
|
|
|
return [str, content[str]];
|
|
|
|
})
|
|
|
|
)
|
|
|
|
);
|
|
|
|
})
|
|
|
|
);
|
|
|
|
|
|
|
|
// Check locales sanity
|
|
|
|
checkLocales(locales, default_lang);
|
|
|
|
|
|
|
|
return locales;
|
2022-07-22 11:46:47 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Builds a dictionary, if a translation is not available,
|
|
|
|
* we fallback to default lang.
|
|
|
|
* @param client Client
|
|
|
|
* @param text Name of string to fetch
|
|
|
|
* @returns the dictionary
|
|
|
|
*/
|
2023-01-17 22:29:15 +01:00
|
|
|
export const getLocalizations = (
|
|
|
|
client: Client,
|
|
|
|
text: string,
|
|
|
|
lowercase = false
|
|
|
|
) => {
|
|
|
|
const data: Record<string, string> = {};
|
|
|
|
|
|
|
|
// Load all the localizations
|
|
|
|
client.locales.forEach((locale, lang) => {
|
|
|
|
// Fetch the text and fallback to default lang if needed
|
|
|
|
// See getLocale for more info on why we *can* fallback
|
|
|
|
let str =
|
|
|
|
locale.get(text) ??
|
|
|
|
client.locales.get(client.config.default_lang)?.get(text);
|
|
|
|
|
|
|
|
// Store it if defined
|
|
|
|
if (str !== undefined) {
|
|
|
|
if (lowercase) {
|
|
|
|
str = str.toLowerCase();
|
|
|
|
}
|
|
|
|
data[lang] = str;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return data;
|
2022-07-22 11:46:47 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the locale data for a lang,
|
|
|
|
* fallback to default language when a string isn't available.
|
|
|
|
* @param client Client
|
|
|
|
* @param lang Lang to fetch
|
|
|
|
* @returns the map with the desired languaged clogged with the default one
|
|
|
|
*/
|
|
|
|
export const getLocale = (client: Client, lang: string) => {
|
2023-01-17 22:29:15 +01:00
|
|
|
// Load default lang
|
|
|
|
const default_locales = client.locales.get(client.config.default_lang);
|
|
|
|
// Load desired lang
|
|
|
|
const desired_locales = client.locales.get(lang);
|
|
|
|
|
|
|
|
// Get text and fallback to default lang if needed
|
|
|
|
//
|
|
|
|
// We can fallback to the default one without any problem
|
|
|
|
// because we make sure that the default language always contains
|
|
|
|
// the desired text, and that the other languages are only translations
|
|
|
|
const locales = new Map();
|
|
|
|
default_locales?.forEach((_, key) => {
|
|
|
|
locales.set(key, desired_locales?.get(key) ?? default_locales.get(key));
|
|
|
|
});
|
|
|
|
|
|
|
|
return locales;
|
2022-07-22 11:46:47 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Show percentage of translation progression.
|
|
|
|
*
|
|
|
|
* Raise an error if the default lang isn't
|
|
|
|
* the lang with most text.
|
|
|
|
* @param locales Locales loaded
|
|
|
|
* @param default_lang default lang
|
|
|
|
* @returns void
|
|
|
|
*/
|
2023-01-17 22:29:15 +01:00
|
|
|
const checkLocales = async (
|
|
|
|
locales: Map<string, Map<string, string>>,
|
|
|
|
default_lang: string
|
|
|
|
) => {
|
|
|
|
// Associate each lang with the number of locale it has
|
|
|
|
let locales_size = new Map<string, number>();
|
|
|
|
locales.forEach((locales_data, lang) => {
|
|
|
|
locales_size.set(lang, locales_data.size);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Sort the map
|
|
|
|
locales_size = new Map(
|
|
|
|
[...locales_size.entries()].sort((a, b) => b[1] - a[1])
|
|
|
|
);
|
|
|
|
|
|
|
|
// Check if default lang is 100%
|
|
|
|
const [max_size_name] = locales_size.keys();
|
|
|
|
const [max_size] = locales_size.values();
|
|
|
|
const default_lang_size = locales_size.get(default_lang) ?? 0;
|
|
|
|
if (max_size > default_lang_size) {
|
|
|
|
// Throw error because in this case we are sure than the security
|
|
|
|
// explained in getLocale isn't true.
|
|
|
|
// However, it is possible that this condition is true
|
|
|
|
// and the security is poor, but it's better than nothing.
|
|
|
|
throw new Error(
|
|
|
|
`The default locale (${default_lang} = ${default_lang_size}) isn't complete ` +
|
|
|
|
`(${max_size_name} = ${max_size}).`
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove the default language as it is used as a reference
|
|
|
|
locales_size.delete(default_lang);
|
|
|
|
|
|
|
|
// Displays the percentages according to the default language
|
|
|
|
// lower is bigger
|
|
|
|
const bar_size = 4;
|
|
|
|
locales_size.forEach((size, lang) => {
|
|
|
|
const percentage = (size / max_size) * 100;
|
|
|
|
// Colored bar part
|
|
|
|
const blocks = " ".repeat(Math.floor(percentage / bar_size));
|
|
|
|
// Blank bar part
|
|
|
|
const blank = " ".repeat(Math.ceil((100 - percentage) / bar_size));
|
|
|
|
const color = () => {
|
|
|
|
switch (true) {
|
|
|
|
case percentage <= 25:
|
|
|
|
// Red
|
|
|
|
return "\x1b[41m";
|
|
|
|
case percentage <= 50:
|
|
|
|
// Mangeta
|
|
|
|
return "\x1b[45m";
|
|
|
|
case percentage <= 75:
|
|
|
|
// Cyan
|
|
|
|
return "\x1b[46m";
|
|
|
|
case percentage <= 100:
|
|
|
|
// Green
|
|
|
|
return "\x1b[42m";
|
|
|
|
default:
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
};
|
|
|
|
const padding = " ".repeat(lang.length === 5 ? 1 : 4);
|
|
|
|
|
|
|
|
console.log(
|
|
|
|
`${padding}${lang} | ${color()}${blocks}\x1b[0m${blank} | ${percentage.toPrecision(
|
|
|
|
3
|
|
|
|
)}%`
|
|
|
|
);
|
|
|
|
});
|
2022-07-22 11:46:47 +02:00
|
|
|
};
|