feat: add useless key scanner

This commit is contained in:
YuMao 2024-12-16 20:29:45 +08:00
parent fca4690f21
commit 412f5132fe
12 changed files with 46 additions and 39 deletions

View File

@ -1972,7 +1972,6 @@
"TXT_CODE_60dd05d5": "Überschreiben Sie das Standard-Image-Arbeitsverzeichnis durch das Datenspeicherverzeichnis",
"TXT_CODE_6259357c": "Das Programm muss länger als 6 Sekunden laufen, bevor ein Stopp erzwungen werden kann!",
"TXT_CODE_6c232c9c": "Wird zum Mounten zusätzlicher Ordner auf dem Host im Container verwendet und unterstützt zwei variable Zeichenfolgen:",
"TXT_CODE_708c10e2": "Paketliste",
"TXT_CODE_75bf9192": "Code verwenden",
"TXT_CODE_8028e95b": "Geben Sie Ihren Panel-Benutzernamen ein. Falls noch kein Konto vorhanden ist, wird ein neues Konto erstellt",
"TXT_CODE_8074a178": "Neues Ablaufdatum:",
@ -2021,4 +2020,4 @@
"TXT_CODE_a0e19f38": "Instanz löschen",
"TXT_CODE_ed81f72d": "Diese Instanz wurde nicht in einem Geschäft gekauft und kann nicht verlängert werden. Bitte kontaktieren Sie den Händler zur Bearbeitung!",
"TXT_CODE_f486dbb4": "Instanz erfolgreich gelöscht"
}
}

View File

@ -1972,7 +1972,6 @@
"TXT_CODE_3ee20639": "Redemption successful, please remember the following",
"TXT_CODE_e1b0aab2": "Password unchanged",
"TXT_CODE_a676f2da": "Got it",
"TXT_CODE_708c10e2": "Package List",
"TXT_CODE_b99cae18": "Products",
"TXT_CODE_163e2d0a": "Display instance specifications when merchant mode is enabled",
"TXT_CODE_48261ab7": "Merchant Info Card",
@ -2019,5 +2018,6 @@
"TXT_CODE_7542201a": "Delete instance-related files simultaneously",
"TXT_CODE_f486dbb4": "Instance deleted successfully",
"TXT_CODE_ed81f72d": "This instance was not purchased from the store and cannot be renewed. Please contact the merchant for processing!",
"TXT_CODE_afabf3ca": "Parsing time failed"
}
"TXT_CODE_afabf3ca": "Parsing time failed",
"TXT_CODE_1548649e": "Edit scheduled tasks"
}

View File

@ -1972,7 +1972,6 @@
"TXT_CODE_60dd05d5": "Anular el directorio de trabajo de imagen predeterminado con el directorio de almacenamiento de datos",
"TXT_CODE_6259357c": "¡El programa debe ejecutarse durante más de 6 segundos antes de que se pueda forzar su detención!",
"TXT_CODE_6c232c9c": "Se utiliza para montar carpetas adicionales en el host en el contenedor, admite dos cadenas de variables:",
"TXT_CODE_708c10e2": "Lista de paquetes",
"TXT_CODE_75bf9192": "Usar código",
"TXT_CODE_8028e95b": "Ingrese su nombre de usuario del panel, se creará una nueva cuenta si no existe",
"TXT_CODE_8074a178": "Nueva fecha de vencimiento:",
@ -2020,4 +2019,4 @@
"TXT_CODE_90508729": "Esta operación eliminará directamente todo el directorio donde se encuentra la instancia y los archivos no se podrán restaurar. ¿Quiere continuar?",
"TXT_CODE_a0e19f38": "Eliminar instancia",
"TXT_CODE_f486dbb4": "Instancia eliminada exitosamente"
}
}

View File

@ -1972,7 +1972,6 @@
"TXT_CODE_60dd05d5": "Remplacer le répertoire de travail de l'image par défaut par le répertoire de stockage de données",
"TXT_CODE_6259357c": "Le programme doit s'exécuter pendant plus de 6 secondes avant de pouvoir être forcé à s'arrêter !",
"TXT_CODE_6c232c9c": "Utilisé pour monter des dossiers supplémentaires sur l'hôte dans le conteneur, prend en charge deux chaînes variables :",
"TXT_CODE_708c10e2": "Liste des paquets",
"TXT_CODE_75bf9192": "Utiliser le code",
"TXT_CODE_8028e95b": "Entrez votre nom d'utilisateur du panel, un nouveau compte sera créé s'il n'existe pas",
"TXT_CODE_8074a178": "Nouvelle date d'expiration :",
@ -2021,4 +2020,4 @@
"TXT_CODE_a0e19f38": "Supprimer l'instance",
"TXT_CODE_ed81f72d": "Cette instance n'a pas été achetée dans un magasin et ne peut pas être renouvelée. Veuillez contacter le marchand pour le traitement !",
"TXT_CODE_f486dbb4": "Instance supprimée avec succès"
}
}

View File

@ -1972,7 +1972,6 @@
"TXT_CODE_60dd05d5": "デフォルトのイメージ作業ディレクトリをデータストレージディレクトリで上書きします",
"TXT_CODE_6259357c": "プログラムは強制的に停止する前に 6 秒以上実行する必要があります。",
"TXT_CODE_6c232c9c": "ホスト上の追加のフォルダーをコンテナーにマウントするために使用され、2 つの変数文字列をサポートします。",
"TXT_CODE_708c10e2": "パッケージリスト",
"TXT_CODE_75bf9192": "コードを使用する",
"TXT_CODE_8028e95b": "パネルのユーザー名を入力してください。存在しない場合は新しいアカウントが作成されます",
"TXT_CODE_8074a178": "新しい有効期限:",
@ -2021,4 +2020,4 @@
"TXT_CODE_a0e19f38": "インスタンスの削除",
"TXT_CODE_ed81f72d": "このインスタンスはストアから購入されたものではないため、更新することはできません。処理については販売者にお問い合わせください。",
"TXT_CODE_f486dbb4": "インスタンスは正常に削除されました"
}
}

View File

@ -1972,7 +1972,6 @@
"TXT_CODE_60dd05d5": "기본 이미지 작업 디렉터리를 데이터 저장소 디렉터리로 재정의",
"TXT_CODE_6259357c": "프로그램을 강제로 중지하려면 6초 이상 실행되어야 합니다!",
"TXT_CODE_6c232c9c": "호스트의 추가 폴더를 컨테이너에 마운트하는 데 사용되며 두 가지 변수 문자열을 지원합니다.",
"TXT_CODE_708c10e2": "패키지 목록",
"TXT_CODE_75bf9192": "코드 사용",
"TXT_CODE_8028e95b": "패널 사용자 이름을 입력하세요. 존재하지 않는 경우 새 계정이 생성됩니다.",
"TXT_CODE_8074a178": "새로운 만료일:",
@ -2021,4 +2020,4 @@
"TXT_CODE_a0e19f38": "인스턴스 삭제",
"TXT_CODE_ed81f72d": "이 인스턴스는 상점에서 구매한 것이 아니므로 갱신할 수 없습니다. 처리하려면 판매자에게 문의하세요.",
"TXT_CODE_f486dbb4": "인스턴스가 삭제되었습니다."
}
}

View File

@ -1972,7 +1972,6 @@
"TXT_CODE_60dd05d5": "Substituir o diretório de trabalho da imagem padrão pelo diretório de armazenamento de dados",
"TXT_CODE_6259357c": "O programa deve ser executado por mais de 6 segundos antes de poder ser forçado a parar!",
"TXT_CODE_6c232c9c": "Usado para montar pastas adicionais no host no contêiner, suporta duas strings variáveis:",
"TXT_CODE_708c10e2": "Lista de pacotes",
"TXT_CODE_75bf9192": "Usar código",
"TXT_CODE_8028e95b": "Digite seu nome de usuário do painel, uma nova conta será criada se não existir",
"TXT_CODE_8074a178": "Nova data de validade:",
@ -2021,4 +2020,4 @@
"TXT_CODE_a0e19f38": "Excluir instância",
"TXT_CODE_ed81f72d": "Esta instância não foi comprada em uma loja e não pode ser renovada. Entre em contato com o comerciante para processamento!",
"TXT_CODE_f486dbb4": "Instância excluída com sucesso"
}
}

View File

@ -1972,7 +1972,6 @@
"TXT_CODE_60dd05d5": "Переопределить рабочий каталог изображения по умолчанию каталогом хранения данных.",
"TXT_CODE_6259357c": "Программа должна работать более 6 секунд, прежде чем ее можно будет принудительно остановить!",
"TXT_CODE_6c232c9c": "Используется для монтирования дополнительных папок на хосте в контейнер, поддерживает две переменные строки:",
"TXT_CODE_708c10e2": "Список пакетов",
"TXT_CODE_75bf9192": "Использовать код",
"TXT_CODE_8028e95b": "Введите имя пользователя вашей панели. Будет создана новая учетная запись, если она не существует.",
"TXT_CODE_8074a178": "Новая дата истечения срока действия:",
@ -2021,4 +2020,4 @@
"TXT_CODE_a0e19f38": "Удалить экземпляр",
"TXT_CODE_ed81f72d": "Этот экземпляр не был куплен в магазине и не может быть продлен. Пожалуйста, обратитесь к продавцу для обработки!",
"TXT_CODE_f486dbb4": "Экземпляр успешно удален"
}
}

View File

@ -1972,7 +1972,6 @@
"TXT_CODE_60dd05d5": "Veri depolama dizini ile varsayılan görüntü çalışma dizinini geçersiz kıl",
"TXT_CODE_6259357c": "Programın durmaya zorlanabilmesi için 6 saniyeden fazla çalışması gerekir!",
"TXT_CODE_6c232c9c": "Ana makinedeki ek klasörleri konteynere eklemek için kullanılır, iki değişken dizeyi destekler:",
"TXT_CODE_708c10e2": "Paket Listesi",
"TXT_CODE_75bf9192": "Kodu Kullan",
"TXT_CODE_8028e95b": "Panel kullanıcı adınızı girin, yoksa yeni hesap oluşturulacak",
"TXT_CODE_8074a178": "Yeni Son Kullanma Tarihi:",
@ -2021,4 +2020,4 @@
"TXT_CODE_ed81f72d": "Bu örnek bir mağazadan satın alınmadı ve yenilenemiyor. İşleme için lütfen satıcıyla iletişime geçin!",
"TXT_CODE_f486dbb4": "Örnek başarıyla silindi",
"TXT_CODE_10088738": "Silmeyi onayla"
}
}

View File

@ -1941,4 +1941,4 @@
"TXT_CODE_6d8bc58d": "儲存失敗單一標籤最多只支援9個字元",
"TXT_CODE_dc9fb6ce": "儲存失敗單一實例最多只支援6個標籤",
"TXT_CODE_2082f659": "注意:如果此處為空,則不會綁定檔案管理中的檔案到容器中!"
}
}

View File

@ -6,7 +6,8 @@
"preview-build": "cd common && npm install && npm run build",
"daemon": "cd daemon && npm run dev",
"frontend": "cd frontend && npm run dev",
"panel": "cd panel && npm run dev"
"panel": "cd panel && npm run dev",
"scan-useless-key": "node scripts/useless-key-scanner.mjs ./languages en_US.json . \".js,.ts,.vue,.tsx,.jsx\" \"node_modules/\""
},
"dependencies": {
"crc": "^4.3.2",

View File

@ -19,27 +19,48 @@ class Database {
keysMap = new Map();
/** @type {Object<string, string>} */
sourceLangFile = {};
sourceLangMap = {};
languageDir = "";
constructor(languageDir = "", languageSourceFileName = "") {
this.sourceLangFile = JSON.parse(
this.languageDir = languageDir;
this.sourceLangMap = JSON.parse(
fs.readFileSync(path.join(languageDir, languageSourceFileName), "utf-8")
);
for (const key in this.sourceLangFile) {
for (const key in this.sourceLangMap) {
this.keysMap.set(key, false);
}
}
rewriteSourceLangFile() {
async rewriteSourceLangFile() {
for (const [key, value] of this.keysMap) {
if (!value) {
delete this.sourceLangFile[key];
delete this.sourceLangMap[key];
}
}
console.log("Rewrite file:", path.join(LANGUAGE_DIR, LANGUAGE_SOURCE_FILE_NAME));
fs.writeFileSync(
path.join(LANGUAGE_DIR, LANGUAGE_SOURCE_FILE_NAME),
JSON.stringify(this.sourceLangFile, null, 2)
JSON.stringify(this.sourceLangMap, null, 2)
);
for (const filename of await fs.promises.readdir(this.languageDir)) {
if (filename.endsWith(".json")) {
const otherLangMap = JSON.parse(
fs.readFileSync(path.join(this.languageDir, filename), "utf-8")
);
for (const key in otherLangMap) {
if (!this.sourceLangMap[key]) {
delete otherLangMap[key];
}
}
console.log("Rewrite other lang file:", path.join(this.languageDir, filename));
fs.writeFileSync(
path.join(this.languageDir, filename),
JSON.stringify(otherLangMap, null, 2)
);
}
}
}
}
@ -85,7 +106,7 @@ function startThread(langKeys, filesPath, database) {
database.keysMap.set(data, true);
}
if (type === "exit") {
console.log(`Thread ${data} scan finished!`);
console.log(`Thread ID: ${data} \tScan finished!`);
resolve(null);
}
});
@ -96,7 +117,7 @@ async function mainThread() {
console.log("process.argv:", process.argv);
const database = new Database(LANGUAGE_DIR, LANGUAGE_SOURCE_FILE_NAME);
const scannedFiles = await scanCodeFiles(CODE_DIR, [], EXCLUDE_FILES);
console.log(`Scanned files (${INCLUDE_EXT_NAMES}):`, scannedFiles.length);
const promises = [];
for (let i = 0; i < scannedFiles.length; i += CONCURRENT_COUNT) {
const filesPath = scannedFiles.slice(i, i + CONCURRENT_COUNT);
@ -104,9 +125,9 @@ async function mainThread() {
}
await Promise.all(promises);
console.log("Rewrite source lang file...");
database.rewriteSourceLangFile();
await database.rewriteSourceLangFile();
console.log("Rewrite source lang file finished!");
const langDir = path.dirname(LANGUAGE_DIR);
process.exit(0);
}
async function worker() {
@ -115,14 +136,7 @@ async function worker() {
/** @type {Map<string, boolean>} */
const langKeys = workerData.langKeys;
console.log(
"New Thread ID:",
threadId,
"Scan queue size:",
filesPath.length,
"Lang keys size:",
langKeys.size
);
console.log("Create new thread ID:", threadId, "\tFiles:", filesPath.length);
async function readOneFile(filePath = "") {
const fileContent = await fs.promises.readFile(filePath, "utf-8");