mirror of
https://github.com/microsoft/vscode.git
synced 2025-12-24 12:19:20 +00:00
Adopt l10n for markdown extension (#165448)
For #164438 Also makes our eslint rules understand `vscode.l10n.t(`
This commit is contained in:
@@ -85,6 +85,27 @@ export = new class NoUnexternalizedStrings implements eslint.Rule.RuleModule {
|
||||
}
|
||||
}
|
||||
|
||||
function visitL10NCall(node: TSESTree.CallExpression) {
|
||||
|
||||
// localize(key, message)
|
||||
const [messageNode] = (<TSESTree.CallExpression>node).arguments;
|
||||
|
||||
// remove message-argument from doubleQuoted list and make
|
||||
// sure it is a string-literal
|
||||
if (isStringLiteral(messageNode)) {
|
||||
doubleQuotedStringLiterals.delete(messageNode);
|
||||
} else if (messageNode.type === AST_NODE_TYPES.ObjectExpression) {
|
||||
for (const prop of messageNode.properties) {
|
||||
if (prop.type === AST_NODE_TYPES.Property) {
|
||||
if (prop.key.type === AST_NODE_TYPES.Identifier && prop.key.name === 'message') {
|
||||
doubleQuotedStringLiterals.delete(prop.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function reportBadStringsAndBadKeys() {
|
||||
// (1)
|
||||
// report all strings that are in double quotes
|
||||
@@ -118,6 +139,7 @@ export = new class NoUnexternalizedStrings implements eslint.Rule.RuleModule {
|
||||
['Literal']: (node: any) => collectDoubleQuotedStrings(node),
|
||||
['ExpressionStatement[directive] Literal:exit']: (node: any) => doubleQuotedStringLiterals.delete(node),
|
||||
['CallExpression[callee.type="MemberExpression"][callee.object.name="nls"][callee.property.name="localize"]:exit']: (node: any) => visitLocalizeCall(node),
|
||||
['CallExpression[callee.type="MemberExpression"][callee.object.property.name="l10n"][callee.property.name="t"]:exit']: (node: any) => visitL10NCall(node),
|
||||
['CallExpression[callee.name="localize"][arguments.length>=2]:exit']: (node: any) => visitLocalizeCall(node),
|
||||
['Program:exit']: reportBadStringsAndBadKeys,
|
||||
};
|
||||
|
||||
@@ -628,7 +628,6 @@
|
||||
"morphdom": "^2.6.1",
|
||||
"picomatch": "^2.3.1",
|
||||
"vscode-languageclient": "^8.0.2",
|
||||
"vscode-nls": "^5.2.0",
|
||||
"vscode-uri": "^3.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { BaseLanguageClient, LanguageClientOptions, NotebookDocumentSyncRegistrationType } from 'vscode-languageclient';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { IMdParser } from '../markdownEngine';
|
||||
import * as proto from './protocol';
|
||||
import { looksLikeMarkdownPath, markdownFileExtensions } from '../util/file';
|
||||
@@ -13,7 +12,6 @@ import { VsCodeMdWorkspace } from './workspace';
|
||||
import { FileWatcherManager } from './fileWatchingManager';
|
||||
import { IDisposable } from '../util/dispose';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export type LanguageClientConstructor = (name: string, description: string, clientOptions: LanguageClientOptions) => BaseLanguageClient;
|
||||
|
||||
@@ -64,7 +62,7 @@ export async function startClient(factory: LanguageClientConstructor, parser: IM
|
||||
},
|
||||
};
|
||||
|
||||
const client = factory('markdown', localize('markdownServer.name', 'Markdown Language Server'), clientOptions);
|
||||
const client = factory('markdown', vscode.l10n.t("Markdown Language Server"), clientOptions);
|
||||
|
||||
client.registerProposedFeatures();
|
||||
|
||||
|
||||
@@ -4,14 +4,12 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { Utils } from 'vscode-uri';
|
||||
import { Command } from '../commandManager';
|
||||
import { createUriListSnippet, getParentDocumentUri, imageFileExtensions } from '../languageFeatures/dropIntoEditor';
|
||||
import { coalesce } from '../util/arrays';
|
||||
import { Schemes } from '../util/schemes';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
|
||||
export class InsertLinkFromWorkspace implements Command {
|
||||
@@ -27,8 +25,8 @@ export class InsertLinkFromWorkspace implements Command {
|
||||
canSelectFiles: true,
|
||||
canSelectFolders: false,
|
||||
canSelectMany: true,
|
||||
openLabel: localize('insertLink.openLabel', "Insert link"),
|
||||
title: localize('insertLink.title', "Insert link"),
|
||||
openLabel: vscode.l10n.t("Insert link"),
|
||||
title: vscode.l10n.t("Insert link"),
|
||||
defaultUri: getDefaultUri(activeEditor.document),
|
||||
});
|
||||
|
||||
@@ -50,10 +48,10 @@ export class InsertImageFromWorkspace implements Command {
|
||||
canSelectFolders: false,
|
||||
canSelectMany: true,
|
||||
filters: {
|
||||
[localize('insertImage.imagesLabel', "Images")]: Array.from(imageFileExtensions)
|
||||
[vscode.l10n.t("Images")]: Array.from(imageFileExtensions)
|
||||
},
|
||||
openLabel: localize('insertImage.openLabel', "Insert image"),
|
||||
title: localize('insertImage.title', "Insert image"),
|
||||
openLabel: vscode.l10n.t("Insert image"),
|
||||
title: vscode.l10n.t("Insert image"),
|
||||
defaultUri: getDefaultUri(activeEditor.document),
|
||||
});
|
||||
|
||||
|
||||
@@ -4,10 +4,8 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { CommandManager } from '../commandManager';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
// Copied from markdown language service
|
||||
export enum DiagnosticCode {
|
||||
@@ -55,7 +53,7 @@ class AddToIgnoreLinksQuickFixProvider implements vscode.CodeActionProvider {
|
||||
const hrefText = (diagnostic as any).data?.hrefText;
|
||||
if (hrefText) {
|
||||
const fix = new vscode.CodeAction(
|
||||
localize('ignoreLinksQuickFix.title', "Exclude '{0}' from link validation.", hrefText),
|
||||
vscode.l10n.t("Exclude '{0}' from link validation.", hrefText),
|
||||
vscode.CodeActionKind.QuickFix);
|
||||
|
||||
fix.command = {
|
||||
|
||||
@@ -5,12 +5,9 @@
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import type * as lsp from 'vscode-languageserver-types';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { MdLanguageClient } from '../client/client';
|
||||
import { Command, CommandManager } from '../commandManager';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
|
||||
export class FindFileReferencesCommand implements Command {
|
||||
|
||||
@@ -23,13 +20,13 @@ export class FindFileReferencesCommand implements Command {
|
||||
public async execute(resource?: vscode.Uri) {
|
||||
resource ??= vscode.window.activeTextEditor?.document.uri;
|
||||
if (!resource) {
|
||||
vscode.window.showErrorMessage(localize('error.noResource', "Find file references failed. No resource provided."));
|
||||
vscode.window.showErrorMessage(vscode.l10n.t("Find file references failed. No resource provided."));
|
||||
return;
|
||||
}
|
||||
|
||||
await vscode.window.withProgress({
|
||||
location: vscode.ProgressLocation.Window,
|
||||
title: localize('progress.title', "Finding file references")
|
||||
title: vscode.l10n.t("Finding file references")
|
||||
}, async (_progress, token) => {
|
||||
const locations = (await this._client.getReferencesToFileInWorkspace(resource!, token)).map(loc => {
|
||||
return new vscode.Location(vscode.Uri.parse(loc.uri), convertRange(loc.range));
|
||||
|
||||
@@ -7,14 +7,12 @@ import * as path from 'path';
|
||||
import * as picomatch from 'picomatch';
|
||||
import * as vscode from 'vscode';
|
||||
import { TextDocumentEdit } from 'vscode-languageclient';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { MdLanguageClient } from '../client/client';
|
||||
import { Delayer } from '../util/async';
|
||||
import { noopToken } from '../util/cancellation';
|
||||
import { Disposable } from '../util/dispose';
|
||||
import { convertRange } from './fileReferences';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
const settingNames = Object.freeze({
|
||||
enabled: 'updateLinksOnFileMove.enabled',
|
||||
@@ -54,7 +52,7 @@ class UpdateLinksOnFileRenameHandler extends Disposable {
|
||||
this._delayer.trigger(() => {
|
||||
vscode.window.withProgress({
|
||||
location: vscode.ProgressLocation.Window,
|
||||
title: localize('renameProgress.title', "Checking for Markdown links to update")
|
||||
title: vscode.l10n.t("Checking for Markdown links to update")
|
||||
}, () => this._flushRenames());
|
||||
});
|
||||
}
|
||||
@@ -121,26 +119,26 @@ class UpdateLinksOnFileRenameHandler extends Disposable {
|
||||
}
|
||||
|
||||
const rejectItem: vscode.MessageItem = {
|
||||
title: localize('reject.title', "No"),
|
||||
title: vscode.l10n.t("No"),
|
||||
isCloseAffordance: true,
|
||||
};
|
||||
|
||||
const acceptItem: vscode.MessageItem = {
|
||||
title: localize('accept.title', "Yes"),
|
||||
title: vscode.l10n.t("Yes"),
|
||||
};
|
||||
|
||||
const alwaysItem: vscode.MessageItem = {
|
||||
title: localize('always.title', "Always"),
|
||||
title: vscode.l10n.t("Always"),
|
||||
};
|
||||
|
||||
const neverItem: vscode.MessageItem = {
|
||||
title: localize('never.title', "Never"),
|
||||
title: vscode.l10n.t("Never"),
|
||||
};
|
||||
|
||||
const choice = await vscode.window.showInformationMessage(
|
||||
newResources.length === 1
|
||||
? localize('prompt', "Update Markdown links for '{0}'?", path.basename(newResources[0].fsPath))
|
||||
: this._getConfirmMessage(localize('promptMoreThanOne', "Update Markdown links for the following {0} files?", newResources.length), newResources), {
|
||||
? vscode.l10n.t("Update Markdown links for '{0}'?", path.basename(newResources[0].fsPath))
|
||||
: this._getConfirmMessage(vscode.l10n.t("Update Markdown links for the following {0} files?", newResources.length), newResources), {
|
||||
modal: true,
|
||||
}, rejectItem, acceptItem, alwaysItem, neverItem);
|
||||
|
||||
@@ -203,9 +201,9 @@ class UpdateLinksOnFileRenameHandler extends Disposable {
|
||||
|
||||
if (resourcesToConfirm.length > MAX_CONFIRM_FILES) {
|
||||
if (resourcesToConfirm.length - MAX_CONFIRM_FILES === 1) {
|
||||
paths.push(localize('moreFile', "...1 additional file not shown"));
|
||||
paths.push(vscode.l10n.t("...1 additional file not shown"));
|
||||
} else {
|
||||
paths.push(localize('moreFiles', "...{0} additional files not shown", resourcesToConfirm.length - MAX_CONFIRM_FILES));
|
||||
paths.push(vscode.l10n.t("...{0} additional files not shown", resourcesToConfirm.length - MAX_CONFIRM_FILES));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as uri from 'vscode-uri';
|
||||
import { ILogger } from '../logging';
|
||||
import { MarkdownItEngine } from '../markdownEngine';
|
||||
@@ -14,7 +13,6 @@ import { WebviewResourceProvider } from '../util/resources';
|
||||
import { MarkdownPreviewConfiguration, MarkdownPreviewConfigurationManager } from './previewConfig';
|
||||
import { ContentSecurityPolicyArbiter, MarkdownPreviewSecurityLevel } from './security';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
/**
|
||||
* Strings used inside the markdown preview.
|
||||
@@ -23,17 +21,11 @@ const localize = nls.loadMessageBundle();
|
||||
* can be localized using our normal localization process.
|
||||
*/
|
||||
const previewStrings = {
|
||||
cspAlertMessageText: localize(
|
||||
'preview.securityMessage.text',
|
||||
'Some content has been disabled in this document'),
|
||||
cspAlertMessageText: vscode.l10n.t("Some content has been disabled in this document"),
|
||||
|
||||
cspAlertMessageTitle: localize(
|
||||
'preview.securityMessage.title',
|
||||
'Potentially unsafe or insecure content has been disabled in the Markdown preview. Change the Markdown preview security setting to allow insecure content or enable scripts'),
|
||||
cspAlertMessageTitle: vscode.l10n.t("Potentially unsafe or insecure content has been disabled in the Markdown preview. Change the Markdown preview security setting to allow insecure content or enable scripts"),
|
||||
|
||||
cspAlertMessageLabel: localize(
|
||||
'preview.securityMessage.label',
|
||||
'Content Disabled Security Warning')
|
||||
cspAlertMessageLabel: vscode.l10n.t("Content Disabled Security Warning")
|
||||
};
|
||||
|
||||
export interface MarkdownContentProviderOutput {
|
||||
@@ -130,7 +122,7 @@ export class MdDocumentRenderer {
|
||||
|
||||
public renderFileNotFoundDocument(resource: vscode.Uri): string {
|
||||
const resourcePath = uri.Utils.basename(resource);
|
||||
const body = localize('preview.notFound', '{0} cannot be found', resourcePath);
|
||||
const body = vscode.l10n.t('{0} cannot be found', resourcePath);
|
||||
return `<!DOCTYPE html>
|
||||
<html>
|
||||
<body class="vscode-body">
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as uri from 'vscode-uri';
|
||||
import { ILogger } from '../logging';
|
||||
import { MarkdownContributionProvider } from '../markdownExtensions';
|
||||
@@ -18,7 +17,6 @@ import { MarkdownPreviewConfigurationManager } from './previewConfig';
|
||||
import { scrollEditorToLine, StartingScrollFragment, StartingScrollLine, StartingScrollLocation } from './scrolling';
|
||||
import { getVisibleLine, LastScrollLocation, TopmostLineMonitor } from './topmostLineMonitor';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
interface WebviewMessage {
|
||||
readonly source: string;
|
||||
@@ -192,9 +190,7 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider {
|
||||
|
||||
case 'previewStyleLoadError':
|
||||
vscode.window.showWarningMessage(
|
||||
localize('onPreviewStyleLoadError',
|
||||
"Could not load 'markdown.styles': {0}",
|
||||
e.body.unloadedStyles.join(', ')));
|
||||
vscode.l10n.t("Could not load 'markdown.styles': {0}", e.body.unloadedStyles.join(', ')));
|
||||
break;
|
||||
}
|
||||
}));
|
||||
@@ -372,7 +368,7 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider {
|
||||
.then((editor) => {
|
||||
revealLineInEditor(editor);
|
||||
}, () => {
|
||||
vscode.window.showErrorMessage(localize('preview.clickOpenFailed', 'Could not open {0}', this._resource.toString()));
|
||||
vscode.window.showErrorMessage(vscode.l10n.t('Could not open {0}', this._resource.toString()));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -773,8 +769,8 @@ export class DynamicMarkdownPreview extends Disposable implements IManagedMarkdo
|
||||
private static _getPreviewTitle(resource: vscode.Uri, locked: boolean): string {
|
||||
const resourceLabel = uri.Utils.basename(resource);
|
||||
return locked
|
||||
? localize('lockedPreviewTitle', '[Preview] {0}', resourceLabel)
|
||||
: localize('previewTitle', 'Preview {0}', resourceLabel);
|
||||
? vscode.l10n.t('[Preview] {0}', resourceLabel)
|
||||
: vscode.l10n.t('Preview {0}', resourceLabel);
|
||||
}
|
||||
|
||||
public get position(): vscode.ViewColumn | undefined {
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { ILogger } from '../logging';
|
||||
import { MarkdownContributionProvider } from '../markdownExtensions';
|
||||
import { Disposable, disposeAll } from '../util/dispose';
|
||||
@@ -16,8 +15,6 @@ import { MarkdownPreviewConfigurationManager } from './previewConfig';
|
||||
import { scrollEditorToLine, StartingScrollFragment } from './scrolling';
|
||||
import { TopmostLineMonitor } from './topmostLineMonitor';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
|
||||
export interface DynamicPreviewSettings {
|
||||
readonly resourceColumn: vscode.ViewColumn;
|
||||
@@ -216,7 +213,7 @@ export class MarkdownPreviewManager extends Disposable implements vscode.Webview
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none';">
|
||||
</head>
|
||||
<body class="error-container">
|
||||
<p>${localize('preview.restoreError', "An unexpected error occurred while restoring the Markdown preview.")}</p>
|
||||
<p>${vscode.l10n.t("An unexpected error occurred while restoring the Markdown preview.")}</p>
|
||||
</body>
|
||||
</html>`;
|
||||
}
|
||||
|
||||
@@ -4,13 +4,9 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { MarkdownPreviewManager } from './previewManager';
|
||||
|
||||
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export const enum MarkdownPreviewSecurityLevel {
|
||||
Strict = 0,
|
||||
AllowInsecureContent = 1,
|
||||
@@ -108,35 +104,33 @@ export class PreviewSecuritySelector {
|
||||
[
|
||||
{
|
||||
type: MarkdownPreviewSecurityLevel.Strict,
|
||||
label: markActiveWhen(currentSecurityLevel === MarkdownPreviewSecurityLevel.Strict) + localize('strict.title', 'Strict'),
|
||||
description: localize('strict.description', 'Only load secure content'),
|
||||
label: markActiveWhen(currentSecurityLevel === MarkdownPreviewSecurityLevel.Strict) + vscode.l10n.t("Strict"),
|
||||
description: vscode.l10n.t("Only load secure content"),
|
||||
}, {
|
||||
type: MarkdownPreviewSecurityLevel.AllowInsecureLocalContent,
|
||||
label: markActiveWhen(currentSecurityLevel === MarkdownPreviewSecurityLevel.AllowInsecureLocalContent) + localize('insecureLocalContent.title', 'Allow insecure local content'),
|
||||
description: localize('insecureLocalContent.description', 'Enable loading content over http served from localhost'),
|
||||
label: markActiveWhen(currentSecurityLevel === MarkdownPreviewSecurityLevel.AllowInsecureLocalContent) + vscode.l10n.t("Allow insecure local content"),
|
||||
description: vscode.l10n.t("Enable loading content over http served from localhost"),
|
||||
}, {
|
||||
type: MarkdownPreviewSecurityLevel.AllowInsecureContent,
|
||||
label: markActiveWhen(currentSecurityLevel === MarkdownPreviewSecurityLevel.AllowInsecureContent) + localize('insecureContent.title', 'Allow insecure content'),
|
||||
description: localize('insecureContent.description', 'Enable loading content over http'),
|
||||
label: markActiveWhen(currentSecurityLevel === MarkdownPreviewSecurityLevel.AllowInsecureContent) + vscode.l10n.t("Allow insecure content"),
|
||||
description: vscode.l10n.t("Enable loading content over http"),
|
||||
}, {
|
||||
type: MarkdownPreviewSecurityLevel.AllowScriptsAndAllContent,
|
||||
label: markActiveWhen(currentSecurityLevel === MarkdownPreviewSecurityLevel.AllowScriptsAndAllContent) + localize('disable.title', 'Disable'),
|
||||
description: localize('disable.description', 'Allow all content and script execution. Not recommended'),
|
||||
label: markActiveWhen(currentSecurityLevel === MarkdownPreviewSecurityLevel.AllowScriptsAndAllContent) + vscode.l10n.t("Disable"),
|
||||
description: vscode.l10n.t("Allow all content and script execution. Not recommended"),
|
||||
}, {
|
||||
type: 'moreinfo',
|
||||
label: localize('moreInfo.title', 'More Information'),
|
||||
label: vscode.l10n.t("More Information"),
|
||||
description: ''
|
||||
}, {
|
||||
type: 'toggle',
|
||||
label: this._cspArbiter.shouldDisableSecurityWarnings()
|
||||
? localize('enableSecurityWarning.title', "Enable preview security warnings in this workspace")
|
||||
: localize('disableSecurityWarning.title', "Disable preview security warning in this workspace"),
|
||||
description: localize('toggleSecurityWarning.description', 'Does not affect the content security level')
|
||||
? vscode.l10n.t("Enable preview security warnings in this workspace")
|
||||
: vscode.l10n.t("Disable preview security warning in this workspace"),
|
||||
description: vscode.l10n.t("Does not affect the content security level")
|
||||
},
|
||||
], {
|
||||
placeHolder: localize(
|
||||
'preview.showPreviewSecuritySelector.title',
|
||||
'Select security settings for Markdown previews in this workspace'),
|
||||
placeHolder: vscode.l10n.t("Select security settings for Markdown previews in this workspace"),
|
||||
});
|
||||
if (!selection) {
|
||||
return;
|
||||
|
||||
@@ -258,11 +258,6 @@ vscode-nls@^5.0.1:
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.1.tgz#ba23fc4d4420d25e7f886c8e83cbdcec47aa48b2"
|
||||
integrity sha512-hHQV6iig+M21lTdItKPkJAaWrxALQb/nqpVffakO4knJOh3DrU2SXOMzUzNgo1eADPzu3qSsJY1weCzvR52q9A==
|
||||
|
||||
vscode-nls@^5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f"
|
||||
integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==
|
||||
|
||||
vscode-uri@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.3.tgz#a95c1ce2e6f41b7549f86279d19f47951e4f4d84"
|
||||
|
||||
Reference in New Issue
Block a user