mirror of
				https://github.com/ImranR98/Obtainium.git
				synced 2025-11-03 23:03:29 +01:00 
			
		
		
		
	Add DeepL translations as placeholders
This commit is contained in:
		@@ -292,15 +292,15 @@
 | 
			
		||||
    "useLatestAssetDateAsReleaseDate": "Použít poslední nahrané dílo jako datum vydání",
 | 
			
		||||
    "defaultPseudoVersioningMethod": "Výchozí metoda pseudoverze",
 | 
			
		||||
    "partialAPKHash": "Částečný hash APK",
 | 
			
		||||
    "APKLinkHash": "APK Link Hash",
 | 
			
		||||
    "APKLinkHash": "Odkaz APK Hash",
 | 
			
		||||
    "directAPKLink": "Přímý odkaz APK",
 | 
			
		||||
    "pseudoVersionInUse": "Pseudoverze se používá",
 | 
			
		||||
    "installed": "Instalováno",
 | 
			
		||||
    "latest": "Nejnovější",
 | 
			
		||||
    "invertRegEx": "Invertovat regulární výraz",
 | 
			
		||||
    "note": "Note",
 | 
			
		||||
    "selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.",
 | 
			
		||||
    "badDownload": "The APK could not be parsed (incompatible or partial download)",
 | 
			
		||||
    "note": "Poznámka",
 | 
			
		||||
    "selfHostedNote": "Rozbalovací seznam \"{}\" lze použít k dosažení vlastních/obvyklých instancí libovolného zdroje.",
 | 
			
		||||
    "badDownload": "APK nelze analyzovat (nekompatibilní nebo částečné stažení)",
 | 
			
		||||
    "removeAppQuestion": {
 | 
			
		||||
        "one": "Odstranit Apku?",
 | 
			
		||||
        "other": "Odstranit Apky?"
 | 
			
		||||
 
 | 
			
		||||
@@ -300,7 +300,7 @@
 | 
			
		||||
    "invertRegEx": "Regulären Ausdruck  invertieren",
 | 
			
		||||
    "note": "Hinweis",
 | 
			
		||||
    "selfHostedNote": "Das „{}“-Dropdown-Menü kann verwendet werden, um selbst gehostete/angepasste Instanzen einer beliebigen Quelle zu erreichen.",
 | 
			
		||||
    "badDownload": "The APK could not be parsed (incompatible or partial download)",
 | 
			
		||||
    "badDownload": "Die APK konnte nicht geparst werden (inkompatibler oder teilweiser Download)",
 | 
			
		||||
    "removeAppQuestion": {
 | 
			
		||||
        "one": "App entfernen?",
 | 
			
		||||
        "other": "Apps entfernen?"
 | 
			
		||||
 
 | 
			
		||||
@@ -80,7 +80,6 @@
 | 
			
		||||
    "removeOutdatedFilter": "Remove Out-of-Date App Filter",
 | 
			
		||||
    "showOutdatedOnly": "Show Out-of-Date Apps Only",
 | 
			
		||||
    "filter": "Filter",
 | 
			
		||||
    "filterActive": "Filter *",
 | 
			
		||||
    "filterApps": "Filter Apps",
 | 
			
		||||
    "appName": "App Name",
 | 
			
		||||
    "author": "Author",
 | 
			
		||||
 
 | 
			
		||||
@@ -298,9 +298,9 @@
 | 
			
		||||
    "installed": "Instalado",
 | 
			
		||||
    "latest": "Versión más reciente",
 | 
			
		||||
    "invertRegEx": "Invertir expresión regular",
 | 
			
		||||
    "note": "Note",
 | 
			
		||||
    "selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.",
 | 
			
		||||
    "badDownload": "The APK could not be parsed (incompatible or partial download)",
 | 
			
		||||
    "note": "Nota",
 | 
			
		||||
    "selfHostedNote": "El desplegable \"{}\" puede utilizarse para acceder a instancias autoalojadas/personalizadas de cualquier fuente.",
 | 
			
		||||
    "badDownload": "No se ha podido analizar el APK (incompatible o descarga parcial)",
 | 
			
		||||
    "removeAppQuestion": {
 | 
			
		||||
        "one": "¿Eliminar Aplicación?",
 | 
			
		||||
        "other": "¿Eliminar Aplicaciones?"
 | 
			
		||||
 
 | 
			
		||||
@@ -299,8 +299,8 @@
 | 
			
		||||
    "latest": "Dernier",
 | 
			
		||||
    "invertRegEx": "Inverser l'expression régulière",
 | 
			
		||||
    "note": "Note",
 | 
			
		||||
    "selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.",
 | 
			
		||||
    "badDownload": "The APK could not be parsed (incompatible or partial download)",
 | 
			
		||||
    "selfHostedNote": "La liste déroulante \"{}\" peut être utilisée pour accéder aux instances auto-hébergées/personnalisées de n'importe quelle source.",
 | 
			
		||||
    "badDownload": "L'APK n'a pas pu être analysé (téléchargement incompatible ou partiel)",
 | 
			
		||||
    "removeAppQuestion": {
 | 
			
		||||
        "one": "Supprimer l'application ?",
 | 
			
		||||
        "other": "Supprimer les applications ?"
 | 
			
		||||
 
 | 
			
		||||
@@ -298,9 +298,9 @@
 | 
			
		||||
    "installed": "Telepített",
 | 
			
		||||
    "latest": "Legújabb",
 | 
			
		||||
    "invertRegEx": "Invertált reguláris kifejezés",
 | 
			
		||||
    "note": "Note",
 | 
			
		||||
    "note": "Megjegyzés:",
 | 
			
		||||
    "selfHostedNote": "A \"{}\" legördülő menü használható bármely forrás saját üzemeltetésű/egyéni példányainak eléréséhez.",
 | 
			
		||||
    "badDownload": "The APK could not be parsed (incompatible or partial download)",
 | 
			
		||||
    "badDownload": "Az APK-t nem lehetett elemezni (inkompatibilis vagy részleges letöltés)",
 | 
			
		||||
    "removeAppQuestion": {
 | 
			
		||||
        "one": "Eltávolítja az alkalmazást?",
 | 
			
		||||
        "other": "Eltávolítja az alkalmazást?"
 | 
			
		||||
 
 | 
			
		||||
@@ -300,7 +300,7 @@
 | 
			
		||||
    "invertRegEx": "Inverti espressione regolare",
 | 
			
		||||
    "note": "Nota",
 | 
			
		||||
    "selfHostedNote": "Il menu a tendina \"{}\" può essere usato per raggiungere istanze autogestite/personali di qualsiasi fonte.",
 | 
			
		||||
    "badDownload": "The APK could not be parsed (incompatible or partial download)",
 | 
			
		||||
    "badDownload": "Non è stato possibile analizzare l'APK (download incompatibile o parziale).",
 | 
			
		||||
    "removeAppQuestion": {
 | 
			
		||||
        "one": "Rimuovere l'app?",
 | 
			
		||||
        "other": "Rimuovere le app?"
 | 
			
		||||
 
 | 
			
		||||
@@ -298,9 +298,9 @@
 | 
			
		||||
    "installed": "インストール済み",
 | 
			
		||||
    "latest": "最新",
 | 
			
		||||
    "invertRegEx": "正規表現を反転",
 | 
			
		||||
    "note": "Note",
 | 
			
		||||
    "selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.",
 | 
			
		||||
    "badDownload": "The APK could not be parsed (incompatible or partial download)",
 | 
			
		||||
    "note": "注",
 | 
			
		||||
    "selfHostedNote": "ドロップダウン\"{}\"を使用すると、あらゆるソースのセルフホスト/カスタムインスタンスにアクセスできます。",
 | 
			
		||||
    "badDownload": "APK を解析できませんでした(互換性がないか、部分的にダウンロードされています)。",
 | 
			
		||||
    "removeAppQuestion": {
 | 
			
		||||
        "one": "アプリを削除しますか?",
 | 
			
		||||
        "other": "アプリを削除しますか?"
 | 
			
		||||
 
 | 
			
		||||
@@ -298,9 +298,9 @@
 | 
			
		||||
    "installed": "Geïnstalleerd",
 | 
			
		||||
    "latest": "Laatste",
 | 
			
		||||
    "invertRegEx": "Reguliere expressie omkeren",
 | 
			
		||||
    "note": "Note",
 | 
			
		||||
    "selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.",
 | 
			
		||||
    "badDownload": "The APK could not be parsed (incompatible or partial download)",
 | 
			
		||||
    "note": "Opmerking",
 | 
			
		||||
    "selfHostedNote": "De \"{}\" dropdown kan gebruikt worden om zelf gehoste/aangepaste instanties van elke bron te bereiken.",
 | 
			
		||||
    "badDownload": "De APK kon niet worden verwerkt (incompatibele of gedeeltelijke download)",
 | 
			
		||||
    "removeAppQuestion": {
 | 
			
		||||
        "one": "App verwijderen?",
 | 
			
		||||
        "other": "Apps verwijderen?"
 | 
			
		||||
 
 | 
			
		||||
@@ -298,9 +298,9 @@
 | 
			
		||||
    "installed": "Zainstalowano",
 | 
			
		||||
    "latest": "Najnowszy",
 | 
			
		||||
    "invertRegEx": "Odwróć wyrażenie regularne",
 | 
			
		||||
    "note": "Note",
 | 
			
		||||
    "selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.",
 | 
			
		||||
    "badDownload": "The APK could not be parsed (incompatible or partial download)",
 | 
			
		||||
    "note": "Uwaga",
 | 
			
		||||
    "selfHostedNote": "Lista rozwijana \"{}\" może być używana do uzyskiwania dostępu do samodzielnie hostowanych / niestandardowych instancji dowolnego źródła.",
 | 
			
		||||
    "badDownload": "Nie można przeanalizować pliku APK (niekompatybilny lub częściowo pobrany).",
 | 
			
		||||
    "removeAppQuestion": {
 | 
			
		||||
        "one": "Usunąć aplikację?",
 | 
			
		||||
        "few": "Usunąć aplikacje?",
 | 
			
		||||
 
 | 
			
		||||
@@ -298,9 +298,9 @@
 | 
			
		||||
    "installed": "Instalado",
 | 
			
		||||
    "latest": "Mais recente",
 | 
			
		||||
    "invertRegEx": "Inverter expressão regular",
 | 
			
		||||
    "note": "Note",
 | 
			
		||||
    "note": "Nota",
 | 
			
		||||
    "selfHostedNote": "O menu suspenso \"{}\" pode ser usado para acessar instâncias auto-hospedadas/personalizadas de qualquer fonte.",
 | 
			
		||||
    "badDownload": "The APK could not be parsed (incompatible or partial download)",
 | 
			
		||||
    "badDownload": "Não foi possível analisar o APK (transferência incompatível ou parcial)",
 | 
			
		||||
    "removeAppQuestion": {
 | 
			
		||||
        "one": "Remover aplicativo?",
 | 
			
		||||
        "other": "Remover aplicativos?"
 | 
			
		||||
 
 | 
			
		||||
@@ -298,9 +298,9 @@
 | 
			
		||||
    "installed": "Установлен",
 | 
			
		||||
    "latest": "Последний",
 | 
			
		||||
    "invertRegEx": "Инвертировать регулярное выражение",
 | 
			
		||||
    "note": "Note",
 | 
			
		||||
    "selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.",
 | 
			
		||||
    "badDownload": "The APK could not be parsed (incompatible or partial download)",
 | 
			
		||||
    "note": "Примечание",
 | 
			
		||||
    "selfHostedNote": "Выпадающий список \"{}\" можно использовать для доступа к самостоятельно размещенным/настроенным экземплярам любого источника.",
 | 
			
		||||
    "badDownload": "APK не удалось разобрать (несовместимая или неполная загрузка)",
 | 
			
		||||
    "removeAppQuestion": {
 | 
			
		||||
        "one": "Удалить приложение?",
 | 
			
		||||
        "other": "Удалить приложения?"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,57 @@
 | 
			
		||||
// Take one (hardcoded) translation file and ensure that all other translation files have the same keys in the same order
 | 
			
		||||
// Then report which other translation files have identical items
 | 
			
		||||
// Then report which other translation files have identical items (or auto-translate them if a DeepL API key is provided)
 | 
			
		||||
 | 
			
		||||
const fs = require('fs')
 | 
			
		||||
const https = require('https')
 | 
			
		||||
 | 
			
		||||
const deeplAPIKey = process.argv[2]
 | 
			
		||||
 | 
			
		||||
const neverAutoTranslate = {
 | 
			
		||||
    steamMobile: ['*'],
 | 
			
		||||
    steamChat: ['*'],
 | 
			
		||||
    root: ['*'],
 | 
			
		||||
    obtainiumExportHyphenatedLowercase: ['*'],
 | 
			
		||||
    theme: ['de'],
 | 
			
		||||
    appId: ['de']
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const translateText = async (text, targetLang, authKey) => {
 | 
			
		||||
    return new Promise((resolve, reject) => {
 | 
			
		||||
        const postData = `text=${encodeURIComponent(text)}&target_lang=${encodeURIComponent(targetLang)}&source_lang=EN`
 | 
			
		||||
        const options = {
 | 
			
		||||
            hostname: 'api-free.deepl.com',
 | 
			
		||||
            port: 443,
 | 
			
		||||
            path: '/v2/translate',
 | 
			
		||||
            method: 'POST',
 | 
			
		||||
            headers: {
 | 
			
		||||
                'Authorization': `DeepL-Auth-Key ${authKey}`,
 | 
			
		||||
                'Content-Type': 'application/x-www-form-urlencoded',
 | 
			
		||||
                'Content-Length': Buffer.byteLength(postData)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        const req = https.request(options, (res) => {
 | 
			
		||||
            let responseData = ''
 | 
			
		||||
            res.on('data', (chunk) => {
 | 
			
		||||
                responseData += chunk
 | 
			
		||||
            })
 | 
			
		||||
            res.on('end', () => {
 | 
			
		||||
                try {
 | 
			
		||||
                    const jsonResponse = JSON.parse(responseData)
 | 
			
		||||
                    resolve(jsonResponse)
 | 
			
		||||
                } catch (error) {
 | 
			
		||||
                    reject(error)
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
        })
 | 
			
		||||
        req.on('error', (error) => {
 | 
			
		||||
            reject(error)
 | 
			
		||||
        })
 | 
			
		||||
        req.write(postData)
 | 
			
		||||
        req.end()
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const main = async () => {
 | 
			
		||||
    const translationsDir = __dirname
 | 
			
		||||
    const templateFile = `${translationsDir}/en.json`
 | 
			
		||||
    const otherFiles = fs.readdirSync(translationsDir).map(f => {
 | 
			
		||||
@@ -11,6 +60,7 @@ const otherFiles = fs.readdirSync(translationsDir).map(f => {
 | 
			
		||||
 | 
			
		||||
    const templateTranslation = require(templateFile)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    otherFiles.forEach(file => {
 | 
			
		||||
        const thisTranslationOriginal = require(file)
 | 
			
		||||
        const thisTranslationNew = {}
 | 
			
		||||
@@ -18,13 +68,52 @@ otherFiles.forEach(file => {
 | 
			
		||||
            thisTranslationNew[k] = thisTranslationOriginal[k] || templateTranslation[k]
 | 
			
		||||
        })
 | 
			
		||||
        fs.writeFileSync(file, `${JSON.stringify(thisTranslationNew, null, '    ')}\n`)
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
otherFiles.forEach(file => {
 | 
			
		||||
    const thisTranslation = require(file)
 | 
			
		||||
    Object.keys(templateTranslation).forEach(k => {
 | 
			
		||||
        if (JSON.stringify(thisTranslation[k]) == JSON.stringify(templateTranslation[k])) {
 | 
			
		||||
            console.log(`${file} :::: ${k} :::: ${JSON.stringify(thisTranslation[k])}`)
 | 
			
		||||
        }
 | 
			
		||||
    })
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
    for (let i in otherFiles) {
 | 
			
		||||
        const file = otherFiles[i]
 | 
			
		||||
        const thisTranslation = require(file)
 | 
			
		||||
        const translationKeys = Object.keys(templateTranslation)
 | 
			
		||||
        for (let j in translationKeys) {
 | 
			
		||||
            const k = translationKeys[j]
 | 
			
		||||
            if (JSON.stringify(thisTranslation[k]) == JSON.stringify(templateTranslation[k])) {
 | 
			
		||||
                const lang = file.split('/').pop().split('.')[0]
 | 
			
		||||
                if (!neverAutoTranslate[k] || (neverAutoTranslate[k].indexOf('*') < 0 && neverAutoTranslate[k].indexOf(lang) < 0)) {
 | 
			
		||||
                    const reportLine = `${file} :::: ${k} :::: ${JSON.stringify(thisTranslation[k])}`
 | 
			
		||||
                    if (deeplAPIKey) {
 | 
			
		||||
                        const translateFunc = async (str) => {
 | 
			
		||||
                            const response = await translateText(str, lang, deeplAPIKey)
 | 
			
		||||
                            if (response.translations) {
 | 
			
		||||
                                return response.translations[0].text
 | 
			
		||||
                            } else {
 | 
			
		||||
                                throw JSON.stringify(response)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        try {
 | 
			
		||||
                            if (typeof templateTranslation[k] == 'string') {
 | 
			
		||||
                                thisTranslation[k] = await translateFunc(thisTranslation[k])
 | 
			
		||||
                            } else {
 | 
			
		||||
                                const subKeys = Object.keys(templateTranslation[k])
 | 
			
		||||
                                for (let n in subKeys) {
 | 
			
		||||
                                    const kk = subKeys[n]
 | 
			
		||||
                                    thisTranslation[k][kk] = await translateFunc(thisTranslation[k][kk])
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        } catch (e) {
 | 
			
		||||
                            if (typeof e == 'string') {
 | 
			
		||||
                                console.log(`${reportLine} :::: ${e}`)
 | 
			
		||||
                            } else {
 | 
			
		||||
                                throw e
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        console.log(reportLine)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        fs.writeFileSync(file, `${JSON.stringify(thisTranslation, null, '    ')}\n`)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
main().catch(e => console.error)
 | 
			
		||||
 
 | 
			
		||||
@@ -288,19 +288,19 @@
 | 
			
		||||
    "useSystemFont": "Använd systemteckensnittet",
 | 
			
		||||
    "systemFontError": "Fel vid laddning av systemteckensnittet: {}",
 | 
			
		||||
    "useVersionCodeAsOSVersion": "Använd appversionskoden som OS-upptäckt version",
 | 
			
		||||
    "requestHeader": "Request header",
 | 
			
		||||
    "requestHeader": "Rubrik för begäran",
 | 
			
		||||
    "useLatestAssetDateAsReleaseDate": "Använd senaste tillgångsuppladdning som releasedatum",
 | 
			
		||||
    "defaultPseudoVersioningMethod": "Standard pseudoversionsmetod",
 | 
			
		||||
    "partialAPKHash": "Delvis APK-hash",
 | 
			
		||||
    "APKLinkHash": "APK Link Hash",
 | 
			
		||||
    "APKLinkHash": "APK-länk Hash",
 | 
			
		||||
    "directAPKLink": "Direkt APK-länk",
 | 
			
		||||
    "pseudoVersionInUse": "En pseudoversion används",
 | 
			
		||||
    "installed": "Installerad",
 | 
			
		||||
    "latest": "Senast",
 | 
			
		||||
    "invertRegEx": "Invertera reguljärt uttryck",
 | 
			
		||||
    "note": "Note",
 | 
			
		||||
    "selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.",
 | 
			
		||||
    "badDownload": "The APK could not be parsed (incompatible or partial download)",
 | 
			
		||||
    "note": "Anmärkning",
 | 
			
		||||
    "selfHostedNote": "Rullgardinsmenyn \"{}\" kan användas för att nå självhostade/anpassade instanser av valfri källa.",
 | 
			
		||||
    "badDownload": "APK kunde inte analyseras (inkompatibel eller partiell nedladdning)",
 | 
			
		||||
    "removeAppQuestion": {
 | 
			
		||||
        "one": "Ta Bort App?",
 | 
			
		||||
        "other": "Ta Bort Appar?"
 | 
			
		||||
 
 | 
			
		||||
@@ -298,9 +298,9 @@
 | 
			
		||||
    "installed": "Kurulmuş",
 | 
			
		||||
    "latest": "En sonuncu",
 | 
			
		||||
    "invertRegEx": "Normal ifadeyi ters çevir",
 | 
			
		||||
    "note": "Note",
 | 
			
		||||
    "selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.",
 | 
			
		||||
    "badDownload": "The APK could not be parsed (incompatible or partial download)",
 | 
			
		||||
    "note": "Not",
 | 
			
		||||
    "selfHostedNote": "\"{}\" açılır menüsü, herhangi bir kaynağın kendi kendine barındırılan/özel örneklerine ulaşmak için kullanılabilir.",
 | 
			
		||||
    "badDownload": "APK ayrıştırılamadı (uyumsuz veya kısmi indirme)",
 | 
			
		||||
    "removeAppQuestion": {
 | 
			
		||||
        "one": "Uygulamayı Kaldır?",
 | 
			
		||||
        "other": "Uygulamaları Kaldır?"
 | 
			
		||||
 
 | 
			
		||||
@@ -298,9 +298,9 @@
 | 
			
		||||
    "installed": "已安装",
 | 
			
		||||
    "latest": "最新的",
 | 
			
		||||
    "invertRegEx": "反转正则表达式",
 | 
			
		||||
    "note": "Note",
 | 
			
		||||
    "selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.",
 | 
			
		||||
    "badDownload": "The APK could not be parsed (incompatible or partial download)",
 | 
			
		||||
    "note": "备注",
 | 
			
		||||
    "selfHostedNote": "{}\"下拉菜单可用于访问任何来源的自托管/自定义实例。",
 | 
			
		||||
    "badDownload": "无法解析 APK(不兼容或部分下载)",
 | 
			
		||||
    "removeAppQuestion": {
 | 
			
		||||
        "one": "是否删除应用?",
 | 
			
		||||
        "other": "是否删除应用?"
 | 
			
		||||
 
 | 
			
		||||
@@ -1038,7 +1038,7 @@ class AppsPageState extends State<AppsPage> {
 | 
			
		||||
          IconButton(
 | 
			
		||||
              color: Theme.of(context).colorScheme.primary,
 | 
			
		||||
              style: const ButtonStyle(visualDensity: VisualDensity.compact),
 | 
			
		||||
              tooltip: isFilterOff ? tr('filter') : tr('filterActive'),
 | 
			
		||||
              tooltip: '${tr('filter')}${isFilterOff ? '' : ' *'}',
 | 
			
		||||
              onPressed: isFilterOff
 | 
			
		||||
                  ? showFilterDialog
 | 
			
		||||
                  : () {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user