未验证 提交 951c98ee 编写于 作者: R Ramya Rao 提交者: GitHub

Use translations from manifest to prompt to install lang pack (#50322)

* Use translations from manifest to prompt to install lang pack

* Add missing file

* Use the right key

* Remove unused variables

* Improve messaging
上级 cdf32b2c
......@@ -13,6 +13,7 @@ export interface ILocalization {
languageName?: string;
languageNameLocalized?: string;
translations: ITranslation[];
minimalTranslations?: { [key: string]: string };
}
export interface ITranslation {
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { localize } from 'vs/nls';
// The strings localized in this file will get pulled into the manifest of the language packs.
// So that they are available for VS Code to use without downloading the entire language pack.
export const minimumTranslatedStrings = {
showLanguagePackExtensions: localize('showLanguagePackExtensions', "The Marketplace has extensions that can localize VS Code in the {0} language"),
searchMarketplace: localize('searchMarketplace', "Search Marketplace"),
installAndRestartMessage: localize('installAndRestartMessage', "Install language pack to localize VS Code in {0} language. Restart VS Code after installing for the language to take effect."),
installAndRestart: localize('installAndRestart', "Install and Restart"),
install: localize('install', 'Install')
};
......@@ -34,7 +34,6 @@ import { getHashedRemotesFromUri } from 'vs/workbench/parts/stats/node/workspace
import { IRequestService } from 'vs/platform/request/node/request';
import { asJson } from 'vs/base/node/request';
import { isNumber } from 'vs/base/common/types';
import { language, LANGUAGE_DEFAULT } from 'vs/base/common/platform';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { INotificationService } from 'vs/platform/notification/common/notification';
......@@ -46,7 +45,6 @@ const empty: { [key: string]: any; } = Object.create(null);
const milliSecondsInADay = 1000 * 60 * 60 * 24;
const choiceNever = localize('neverShowAgain', "Don't Show Again");
const searchMarketplace = localize('searchMarketplace', "Search Marketplace");
const coreLanguages = ['de', 'es', 'fr', 'it', 'ja', 'ko', 'ru', 'tr', 'zh-cn', 'zh-tw'];
interface IDynamicWorkspaceRecommendations {
remoteSet: string[];
......@@ -93,7 +91,6 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
this._extensionsRecommendationsUrl = product.extensionsGallery.recommendationsUrl;
}
this.getLanguageExtensionRecommendations();
this.getCachedDynamicWorkspaceRecommendations();
this._suggestFileBasedRecommendations();
this.promptWorkspaceRecommendationsPromise = this._suggestWorkspaceRecommendations();
......@@ -132,90 +129,6 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
return this._galleryService.isEnabled() && !this.environmentService.extensionDevelopmentPath;
}
private getLanguageExtensionRecommendations() {
const config = this.configurationService.getValue<IExtensionsConfiguration>(ConfigurationKey);
const languagePackSuggestionIgnoreList = <string[]>JSON.parse(this.storageService.get
('extensionsAssistant/languagePackSuggestionIgnore', StorageScope.GLOBAL, '[]'));
if (!language
|| language === LANGUAGE_DEFAULT
|| coreLanguages.some(x => language === x || language.indexOf(x + '-') === 0)
|| config.ignoreRecommendations
|| config.showRecommendationsOnlyOnDemand
|| languagePackSuggestionIgnoreList.indexOf(language) > -1) {
return;
}
this.extensionsService.getInstalled(LocalExtensionType.User).then(locals => {
for (var i = 0; i < locals.length; i++) {
if (locals[i].manifest
&& locals[i].manifest.contributes
&& Array.isArray(locals[i].manifest.contributes.localizations)
&& locals[i].manifest.contributes.localizations.some(x => x.languageId === language)) {
return;
}
}
this._galleryService.query({ text: `tag:lp-${language}` }).then(pager => {
if (!pager || !pager.firstPage || !pager.firstPage.length) {
return;
}
this.notificationService.prompt(
Severity.Info,
localize('showLanguagePackExtensions', "The Marketplace has extensions that can help localizing VS Code to '{0}' locale", language),
[{
label: searchMarketplace,
run: () => {
/* __GDPR__
"languagePackSuggestion:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('languagePackSuggestion:popup', { userReaction: 'ok', language });
this.viewletService.openViewlet('workbench.view.extensions', true)
.then(viewlet => viewlet as IExtensionsViewlet)
.then(viewlet => {
viewlet.search(`tag:lp-${language}`);
viewlet.focus();
});
}
},
{
label: choiceNever,
isSecondary: true,
run: () => {
languagePackSuggestionIgnoreList.push(language);
this.storageService.store(
'extensionsAssistant/languagePackSuggestionIgnore',
JSON.stringify(languagePackSuggestionIgnoreList),
StorageScope.GLOBAL
);
/* __GDPR__
"languagePackSuggestion:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('languagePackSuggestion:popup', { userReaction: 'neverShowAgain', language });
}
}],
() => {
/* __GDPR__
"languagePackSuggestion:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"language": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('languagePackSuggestion:popup', { userReaction: 'cancelled', language });
}
);
});
});
}
getAllRecommendationsWithReason(): { [id: string]: { reasonId: ExtensionRecommendationReason, reasonText: string }; } {
let output: { [id: string]: { reasonId: ExtensionRecommendationReason, reasonText: string }; } = Object.create(null);
......
......@@ -23,11 +23,12 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
import URI from 'vs/base/common/uri';
import { join } from 'vs/base/common/paths';
import { IWindowsService } from 'vs/platform/windows/common/windows';
import { IStorageService, StorageScope, } from 'vs/platform/storage/common/storage';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { TPromise } from 'vs/base/common/winjs.base';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { VIEWLET_ID as EXTENSIONS_VIEWLET_ID, IExtensionsViewlet } from 'vs/workbench/parts/extensions/common/extensions';
import product from 'vs/platform/node/product';
import { minimumTranslatedStrings } from 'vs/platform/node/minimalTranslations';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
// Register action to configure locale and related settings
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
......@@ -43,7 +44,8 @@ export class LocalizationWorkbenchContribution extends Disposable implements IWo
@IStorageService private storageService: IStorageService,
@IExtensionManagementService private extensionManagementService: IExtensionManagementService,
@IExtensionGalleryService private galleryService: IExtensionGalleryService,
@IViewletService private viewletService: IViewletService
@IViewletService private viewletService: IViewletService,
@ITelemetryService private telemetryService: ITelemetryService
) {
super();
this.updateLocaleDefintionSchema();
......@@ -96,6 +98,7 @@ export class LocalizationWorkbenchContribution extends Disposable implements IWo
private checkAndInstall(): void {
const language = platform.language;
const locale = platform.locale;
if (language !== 'en' && language !== 'en_us') {
this.isLanguageInstalled(language)
.then(installed => {
......@@ -115,53 +118,116 @@ export class LocalizationWorkbenchContribution extends Disposable implements IWo
return;
}
const bundledTranslations = (product['bundledTranslations'] || {})[platform.locale];
if (language === platform.locale || !bundledTranslations || !bundledTranslations['languageName']) {
const languagePackSuggestionIgnoreList = <string[]>JSON.parse(this.storageService.get
('extensionsAssistant/languagePackSuggestionIgnore', StorageScope.GLOBAL, '[]'));
if (language === locale || languagePackSuggestionIgnoreList.indexOf(language) > -1) {
return;
}
// The initial value for below dont get used. We just have it here so that they get localized.
// The localized strings get pulled into the "product.json" file during endgame to get shipped
let searchForLanguagePacks = localize('searchForLanguagePacks', "There are extensions in the Marketplace that can localize VS Code using the ${0} language.", bundledTranslations['languageName']);
let searchMarketplace = localize('searchMarketplace', "Search Marketplace");
let dontShowAgain = localize('neverAgain', "Don't Show Again");
this.isLanguageInstalled(locale)
.then(installed => {
if (installed) {
return;
}
searchForLanguagePacks = bundledTranslations['searchForLanguagePacks'];
searchMarketplace = bundledTranslations['searchMarketplace'];
dontShowAgain = bundledTranslations['neverAgain'];
const ceintlExtensionSearch = this.galleryService.query({ names: [`MS-CEINTL.vscode-language-pack-${locale}`], pageSize: 1 });
const tagSearch = this.galleryService.query({ text: `tag:lp-${locale}`, pageSize: 1 });
const dontShowSearchLanguagePacksAgainKey = 'language.install.donotask';
let dontShowSearchForLanguages = JSON.parse(this.storageService.get(dontShowSearchLanguagePacksAgainKey, StorageScope.GLOBAL, '[]'));
if (!Array.isArray(dontShowSearchForLanguages)) {
dontShowSearchForLanguages = [];
}
TPromise.join([ceintlExtensionSearch, tagSearch]).then(([ceintlResult, tagResult]) => {
if (ceintlResult.total === 0 && tagResult.total === 0) {
return;
}
if (dontShowSearchForLanguages.indexOf(platform.locale) > -1
|| !searchForLanguagePacks
|| !searchMarketplace
|| !dontShowAgain) {
return;
}
const extensionToInstall = ceintlResult.total === 1 ? ceintlResult.firstPage[0] : tagResult.total === 1 ? tagResult.firstPage[0] : null;
const extensionToFetchTranslationsFrom = extensionToInstall || tagResult.total > 0 ? tagResult.firstPage[0] : null;
this.notificationService.prompt(Severity.Info, searchForLanguagePacks,
[
{
label: searchMarketplace, run: () => {
this.viewletService.openViewlet(EXTENSIONS_VIEWLET_ID, true)
.then(viewlet => viewlet as IExtensionsViewlet)
.then(viewlet => {
viewlet.search(`tag:lp-${platform.locale}`);
viewlet.focus();
});
if (!extensionToFetchTranslationsFrom || !extensionToFetchTranslationsFrom.assets.manifest) {
return;
}
},
{
label: dontShowAgain, run: () => {
dontShowSearchForLanguages.push(language);
this.storageService.store(dontShowSearchLanguagePacksAgainKey, StorageScope.GLOBAL, dontShowSearchForLanguages);
}
}
]);
this.galleryService.getManifest(extensionToFetchTranslationsFrom).then(x => {
if (!x.contributes || !x.contributes.localizations) {
return;
}
const locContribution = x.contributes.localizations.filter(x => x.languageId.toLowerCase() === locale)[0];
if (!locContribution) {
return;
}
const translations = {
...minimumTranslatedStrings,
...(locContribution.minimalTranslations || {})
};
const logUserReaction = (userReaction: string) => {
/* __GDPR__
"languagePackSuggestion:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"language": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('languagePackSuggestion:popup', { userReaction, language });
};
const searchAction = {
label: translations['searchMarketplace'],
run: () => {
logUserReaction('search');
this.viewletService.openViewlet(EXTENSIONS_VIEWLET_ID, true)
.then(viewlet => viewlet as IExtensionsViewlet)
.then(viewlet => {
viewlet.search(`tag:lp-${locale}`);
viewlet.focus();
});
}
};
const installAction = {
label: translations['install'],
run: () => {
logUserReaction('install');
this.installExtension(extensionToInstall);
}
};
const installAndRestartAction = {
label: translations['installAndRestart'],
run: () => {
logUserReaction('installAndRestart');
this.installExtension(extensionToInstall).then(() => this.windowsService.relaunch({}));
}
};
const mainActions = extensionToInstall ? [installAndRestartAction, installAction] : [searchAction];
const promptMessage = translations[extensionToInstall ? 'installAndRestartMessage' : 'showLanguagePackExtensions']
.replace('{0}', locContribution.languageNameLocalized || locContribution.languageName || locale);
this.notificationService.prompt(
Severity.Info,
promptMessage,
[...mainActions,
{
label: localize('neverAgain', "Don't Show Again"),
isSecondary: true,
run: () => {
languagePackSuggestionIgnoreList.push(language);
this.storageService.store(
'extensionsAssistant/languagePackSuggestionIgnore',
JSON.stringify(languagePackSuggestionIgnoreList),
StorageScope.GLOBAL
);
logUserReaction('neverShowAgain');
}
}],
() => {
logUserReaction('cancelled');
}
);
});
});
});
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册