2025-02-17 02:07:21 +01:00
|
|
|
/*
|
|
|
|
|
* Copyright (C) Contributors to the Suwayomi project
|
|
|
|
|
*
|
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
WeblateChangePayload,
|
|
|
|
|
WeblateChangeResult,
|
|
|
|
|
WeblateLanguagePayload,
|
2025-02-17 02:29:50 +01:00
|
|
|
WeblateLanguageStatistic,
|
2025-02-17 02:07:21 +01:00
|
|
|
WeblateUserPayload,
|
|
|
|
|
} from '@/../tools/scripts/weblate/Weblate.types.ts';
|
2025-08-02 23:13:50 +02:00
|
|
|
import 'dotenv/config';
|
2025-02-17 02:29:50 +01:00
|
|
|
import { TRANSLATED_PERCENT_THRESHOLD } from '@/../tools/scripts/weblate/Weblate.constants.ts';
|
2025-02-17 02:07:21 +01:00
|
|
|
|
2025-08-02 23:13:50 +02:00
|
|
|
export const fetchData = async <T = any>(url: string): Promise<T> => {
|
2025-02-17 02:07:21 +01:00
|
|
|
const response = await fetch(url, {
|
|
|
|
|
method: 'GET',
|
|
|
|
|
headers: {
|
2025-08-02 23:13:50 +02:00
|
|
|
...(process.env.WEBLATE_TOKEN ? { Authorization: `Token ${process.env.WEBLATE_TOKEN}` } : {}),
|
2025-02-17 02:07:21 +01:00
|
|
|
Accept: 'application/json',
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!response.ok) {
|
|
|
|
|
throw new Error(`Weblate request failed with status ${response.status} - ${response.statusText}`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return response.json();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const fetchWeblateChanges = async (
|
|
|
|
|
url: string,
|
|
|
|
|
weblateChangeResults: WeblateChangeResult[] = [],
|
|
|
|
|
): Promise<WeblateChangeResult[]> => {
|
2025-08-02 23:13:50 +02:00
|
|
|
const weblateChangePage = await fetchData<WeblateChangePayload>(url);
|
2025-02-17 02:07:21 +01:00
|
|
|
|
|
|
|
|
if (!weblateChangePage.next) {
|
|
|
|
|
return [...weblateChangePage.results, ...weblateChangeResults];
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-02 23:13:50 +02:00
|
|
|
return fetchWeblateChanges(weblateChangePage.next, [...weblateChangePage.results, ...weblateChangeResults]);
|
2025-02-17 02:07:21 +01:00
|
|
|
};
|
|
|
|
|
|
2025-08-02 23:13:50 +02:00
|
|
|
export const getUsername = async (url: string): Promise<string> => {
|
|
|
|
|
const userPayload = await fetchData<WeblateUserPayload>(url);
|
2025-02-17 02:07:21 +01:00
|
|
|
return userPayload.full_name;
|
|
|
|
|
};
|
|
|
|
|
|
2025-08-02 23:13:50 +02:00
|
|
|
export const getLanguageName = async (url: string): Promise<string> => {
|
|
|
|
|
const languagePayload = await fetchData<WeblateLanguagePayload>(url);
|
2025-02-17 02:07:21 +01:00
|
|
|
return languagePayload.language.name.replace(/\(([a-zA-Z]+) Han script\)/g, '($1)');
|
|
|
|
|
};
|
|
|
|
|
|
2025-02-17 02:29:50 +01:00
|
|
|
export const fetchWeblateLanguageStats = async () =>
|
2025-08-02 23:13:50 +02:00
|
|
|
fetchData('https://hosted.weblate.org/api/components/suwayomi/suwayomi-webui/statistics/?format=json-flat');
|
2025-02-17 02:29:50 +01:00
|
|
|
|
2025-02-17 02:07:21 +01:00
|
|
|
const dateRegex = /[0-9]{4}-[0-9]{2}-[0-9]{2}/g;
|
|
|
|
|
const isValidIS08601Date = (date: string): boolean => !!date.match(dateRegex);
|
|
|
|
|
export const validateWeblateDates = (afterDate: string, beforeDate: string) => {
|
|
|
|
|
if (!isValidIS08601Date(afterDate) || !isValidIS08601Date(beforeDate)) {
|
|
|
|
|
throw new Error(
|
|
|
|
|
`The passed timestamps are not properly formatted. They have to match "${dateRegex}" (e.g. 2024-05-11)`,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
};
|
2025-02-17 02:29:50 +01:00
|
|
|
|
|
|
|
|
export const normalizeCode = (code: string): string => code.replace(/[-_]/g, '');
|
|
|
|
|
|
|
|
|
|
export const getWeblateLanguageStatsFor = (
|
|
|
|
|
code: string,
|
|
|
|
|
stats: WeblateLanguageStatistic[],
|
|
|
|
|
): WeblateLanguageStatistic => {
|
|
|
|
|
const langaugeStats = stats.find((stat) => normalizeCode(stat.code) === normalizeCode(code));
|
|
|
|
|
|
|
|
|
|
if (!langaugeStats) {
|
2026-01-10 19:45:02 +01:00
|
|
|
throw new Error(`Weblate language stats for "${code}" do not exist`);
|
2025-02-17 02:29:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return langaugeStats;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const meetsTranslatedPercentThreshold = (
|
|
|
|
|
translatedPercent: number,
|
|
|
|
|
threshold: number = TRANSLATED_PERCENT_THRESHOLD,
|
|
|
|
|
): boolean => translatedPercent >= threshold;
|