mirror of
https://github.com/microsoft/vscode.git
synced 2025-12-20 02:08:47 +00:00
Fix offending l10n.t call and add an eslint rule to prevent it from happening (#277577)
ref https://github.com/microsoft/vscode/issues/277576
This commit is contained in:
committed by
GitHub
parent
9f56e2671c
commit
8711dcb9da
@@ -0,0 +1,90 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import * as eslint from 'eslint';
|
||||||
|
import { TSESTree } from '@typescript-eslint/utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevents the use of template literals in localization function calls.
|
||||||
|
*
|
||||||
|
* vscode.l10n.t() and nls.localize() cannot handle string templating.
|
||||||
|
* Use placeholders instead: vscode.l10n.t('Message {0}', value)
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
* ❌ vscode.l10n.t(`Message ${value}`)
|
||||||
|
* ✅ vscode.l10n.t('Message {0}', value)
|
||||||
|
*
|
||||||
|
* ❌ nls.localize('key', `Message ${value}`)
|
||||||
|
* ✅ nls.localize('key', 'Message {0}', value)
|
||||||
|
*/
|
||||||
|
export default new class NoLocalizationTemplateLiterals implements eslint.Rule.RuleModule {
|
||||||
|
|
||||||
|
readonly meta: eslint.Rule.RuleMetaData = {
|
||||||
|
messages: {
|
||||||
|
noTemplateLiteral: 'Template literals cannot be used in localization calls. Use placeholders like {0}, {1} instead.'
|
||||||
|
},
|
||||||
|
docs: {
|
||||||
|
description: 'Prevents template literals in vscode.l10n.t() and nls.localize() calls',
|
||||||
|
},
|
||||||
|
schema: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
|
||||||
|
|
||||||
|
function checkCallExpression(node: TSESTree.CallExpression) {
|
||||||
|
const callee = node.callee;
|
||||||
|
let isLocalizationCall = false;
|
||||||
|
let isNlsLocalize = false;
|
||||||
|
|
||||||
|
// Check for vscode.l10n.t()
|
||||||
|
if (callee.type === 'MemberExpression') {
|
||||||
|
const object = callee.object;
|
||||||
|
const property = callee.property;
|
||||||
|
|
||||||
|
// vscode.l10n.t
|
||||||
|
if (object.type === 'MemberExpression') {
|
||||||
|
const outerObject = object.object;
|
||||||
|
const outerProperty = object.property;
|
||||||
|
if (outerObject.type === 'Identifier' && outerObject.name === 'vscode' &&
|
||||||
|
outerProperty.type === 'Identifier' && outerProperty.name === 'l10n' &&
|
||||||
|
property.type === 'Identifier' && property.name === 't') {
|
||||||
|
isLocalizationCall = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// l10n.t or nls.localize or any *.localize
|
||||||
|
if (object.type === 'Identifier' && property.type === 'Identifier') {
|
||||||
|
if (object.name === 'l10n' && property.name === 't') {
|
||||||
|
isLocalizationCall = true;
|
||||||
|
} else if (property.name === 'localize') {
|
||||||
|
isLocalizationCall = true;
|
||||||
|
isNlsLocalize = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isLocalizationCall) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For vscode.l10n.t(message, ...args) - check the first argument (message)
|
||||||
|
// For nls.localize(key, message, ...args) - check first two arguments (key and message)
|
||||||
|
const argsToCheck = isNlsLocalize ? 2 : 1;
|
||||||
|
for (let i = 0; i < argsToCheck && i < node.arguments.length; i++) {
|
||||||
|
const arg = node.arguments[i];
|
||||||
|
if (arg && arg.type === 'TemplateLiteral' && arg.expressions.length > 0) {
|
||||||
|
context.report({
|
||||||
|
node: arg,
|
||||||
|
messageId: 'noTemplateLiteral'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
CallExpression: (node: any) => checkCallExpression(node as TSESTree.CallExpression)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -90,6 +90,7 @@ export default tseslint.config(
|
|||||||
'local/code-no-reader-after-await': 'warn',
|
'local/code-no-reader-after-await': 'warn',
|
||||||
'local/code-no-observable-get-in-reactive-context': 'warn',
|
'local/code-no-observable-get-in-reactive-context': 'warn',
|
||||||
'local/code-policy-localization-key-match': 'warn',
|
'local/code-policy-localization-key-match': 'warn',
|
||||||
|
'local/code-no-localization-template-literals': 'error',
|
||||||
'local/code-no-deep-import-of-internal': ['error', { '.*Internal': true, 'searchExtTypesInternal': false }],
|
'local/code-no-deep-import-of-internal': ['error', { '.*Internal': true, 'searchExtTypesInternal': false }],
|
||||||
'local/code-layering': [
|
'local/code-layering': [
|
||||||
'warn',
|
'warn',
|
||||||
|
|||||||
@@ -367,7 +367,7 @@ class TypeScriptQuickFixProvider implements vscode.CodeActionProvider<VsCodeCode
|
|||||||
let title = action.description;
|
let title = action.description;
|
||||||
if (action.fixName === fixNames.classIncorrectlyImplementsInterface) {
|
if (action.fixName === fixNames.classIncorrectlyImplementsInterface) {
|
||||||
title = vscode.l10n.t('{0} with AI', action.description);
|
title = vscode.l10n.t('{0} with AI', action.description);
|
||||||
message = vscode.l10n.t(`Implement the stubbed-out class members for ${document.getText(diagnostic.range)} with a useful implementation.`);
|
message = vscode.l10n.t('Implement the stubbed-out class members for {0} with a useful implementation.', document.getText(diagnostic.range));
|
||||||
expand = { kind: 'code-action', action };
|
expand = { kind: 'code-action', action };
|
||||||
} else if (action.fixName === fixNames.fixClassDoesntImplementInheritedAbstractMember) {
|
} else if (action.fixName === fixNames.fixClassDoesntImplementInheritedAbstractMember) {
|
||||||
title = vscode.l10n.t('{0} with AI', action.description);
|
title = vscode.l10n.t('{0} with AI', action.description);
|
||||||
|
|||||||
Reference in New Issue
Block a user