Skip to content

Commit

Permalink
Merge pull request #385 from CodinGame/localization
Browse files Browse the repository at this point in the history
Localization service override
  • Loading branch information
CGNonofr authored Apr 9, 2024
2 parents 11f634c + 86c63b0 commit 689fcbc
Show file tree
Hide file tree
Showing 14 changed files with 257 additions and 66 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,8 @@ Additionally, several packages that include the VSCode version of some services
- Survey/feedback support
- **Update**
- Update detection, release notes...
- **Localization**
- Register callbacks to update the display language from the VSCode UI (either from the `Set Display Language` command or from the extension gallery extension packs)

Usage:

Expand Down
23 changes: 22 additions & 1 deletion demo/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@
"@codingame/monaco-vscode-workspace-trust-service-override": "file:../dist/service-override-workspace-trust",
"@codingame/monaco-vscode-xml-default-extension": "file:../dist/default-extension-xml",
"@codingame/monaco-vscode-yaml-default-extension": "file:../dist/default-extension-yaml",
"@codingame/monaco-vscode-localization-service-override": "file:../dist/service-override-localization",
"ansi-colors": "^4.1.3",
"dockerode": "^4.0.2",
"express": "^4.19.2",
Expand Down
13 changes: 0 additions & 13 deletions demo/src/main.common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,6 @@ void getApi().then(async vscode => {
code: 42
}])

const locale = new URLSearchParams(window.location.search).get('locale') ?? ''
const select: HTMLSelectElement = document.querySelector('#localeSelect')!
select.value = locale
select.addEventListener('change', () => {
const url = new URL(window.location.href)
if (select.value !== '') {
url.searchParams.set('locale', select.value)
} else {
url.searchParams.delete('locale')
}
window.location.href = url.toString()
})

document.querySelector('#toggleFullWorkbench')!.addEventListener('click', async () => {
const url = new URL(window.location.href)
if (url.searchParams.get('mode') === 'full-workbench') {
Expand Down
66 changes: 65 additions & 1 deletion demo/src/setup.common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import getSpeechServiceOverride from '@codingame/monaco-vscode-speech-service-ov
import getSurveyServiceOverride from '@codingame/monaco-vscode-survey-service-override'
import getUpdateServiceOverride from '@codingame/monaco-vscode-update-service-override'
import getExplorerServiceOverride from '@codingame/monaco-vscode-explorer-service-override'
import getLocalizationServiceOverride from '@codingame/monaco-vscode-localization-service-override'
import { EnvironmentOverride } from 'vscode/workbench'
import { Worker } from './tools/crossOriginWorker'
import defaultKeybindings from './user/keybindings.json?raw'
Expand Down Expand Up @@ -248,6 +249,8 @@ export const constructOptions: IWorkbenchConstructionOptions = {
message: 'Welcome in monaco-vscode-api demo'
},
productConfiguration: {
nameShort: 'monaco-vscode-api',
nameLong: 'monaco-vscode-api',
extensionsGallery: {
serviceUrl: 'https://open-vsx.org/vscode/gallery',
itemUrl: 'https://open-vsx.org/vscode/item',
Expand Down Expand Up @@ -322,5 +325,66 @@ export const commonServices: IEditorOverrideServices = {
...getSpeechServiceOverride(),
...getSurveyServiceOverride(),
...getUpdateServiceOverride(),
...getExplorerServiceOverride()
...getExplorerServiceOverride(),
...getLocalizationServiceOverride({
async clearLocale () {
const url = new URL(window.location.href)
url.searchParams.delete('locale')
window.history.pushState(null, '', url.toString())
},
async setLocale (id) {
const url = new URL(window.location.href)
url.searchParams.set('locale', id)
window.history.pushState(null, '', url.toString())
},
availableLanguages: [{
locale: 'en',
languageName: 'English'
}, {
locale: 'cs',
languageName: 'Czech'
}, {
locale: 'de',
languageName: 'German'
}, {
locale: 'es',
languageName: 'Spanish'
}, {
locale: 'fr',
languageName: 'French'
}, {
locale: 'it',
languageName: 'Italian'
}, {
locale: 'ja',
languageName: 'Japanese'
}, {
locale: 'ko',
languageName: 'Korean'
}, {
locale: 'pl',
languageName: 'Polish'
}, {
locale: 'pt-br',
languageName: 'Portuguese (Brazil)'
}, {
locale: 'qps-ploc',
languageName: 'Pseudo Language'
}, {
locale: 'ru',
languageName: 'Russian'
}, {
locale: 'tr',
languageName: 'Turkish'
}, {
locale: 'zh-hans',
languageName: 'Chinese (Simplified)'
}, {
locale: 'zh-hant',
languageName: 'Chinese (Traditional)'
}, {
locale: 'en',
languageName: 'English'
}]
})
}
19 changes: 0 additions & 19 deletions demo/src/setup.views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,25 +41,6 @@ container.innerHTML = `
<br />
<button id="togglePanel">Toggle Panel</button>
<button id="toggleAuxiliary">Toggle Secondary Panel</button>
<br />
<label for="localeSelect">Language:</label>
<select id="localeSelect">
<option value="">English</option>
<option value="cs">Czech</option>
<option value="de">German</option>
<option value="es">Spanish</option>
<option value="fr">French</option>
<option value="it">Italian</option>
<option value="ja">Japanese</option>
<option value="ko">Korean</option>
<option value="pl">Polish</option>
<option value="pt-br">Portuguese (Brazil)</option>
<option value="qps-ploc">Pseudo Language</option>
<option value="ru">Russian</option>
<option value="tr">Turkish</option>
<option value="zh-hans">Chinese (Simplified)</option>
<option value="zh-hant">Chinese (Traditional)</option>
</select>
</div>
<div style="display: flex; flex: none; border: 1px solid var(--vscode-editorWidget-border);">
<div id="sidebar-right" style="max-width: 500px"></div>
Expand Down
19 changes: 0 additions & 19 deletions demo/src/setup.workbench.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,6 @@ buttons.innerHTML = `
<br />
<button id="togglePanel">Toggle Panel</button>
<button id="toggleAuxiliary">Toggle Secondary Panel</button>
<br />
<label for="localeSelect">Language:</label>
<select id="localeSelect">
<option value="">English</option>
<option value="cs">Czech</option>
<option value="de">German</option>
<option value="es">Spanish</option>
<option value="fr">French</option>
<option value="it">Italian</option>
<option value="ja">Japanese</option>
<option value="ko">Korean</option>
<option value="pl">Polish</option>
<option value="pt-br">Portuguese (Brazil)</option>
<option value="qps-ploc">Pseudo Language</option>
<option value="ru">Russian</option>
<option value="tr">Turkish</option>
<option value="zh-hans">Chinese (Simplified)</option>
<option value="zh-hant">Chinese (Traditional)</option>
</select>
</div>
`
document.body.append(buttons)
Expand Down
2 changes: 1 addition & 1 deletion rollup/rollup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ const REMOVE_WORKBENCH_CONTRIBUTIONS = new Set([
/**
* root files that should never be extracted from the main package to a service override package
*/
const SHARED_ROOT_FILES_BETWEEN_PACKAGES = ['services.js', 'extensions.js', 'monaco.js', 'assets.js', 'lifecycle.js', 'workbench.js', 'missing-services.js']
const SHARED_ROOT_FILES_BETWEEN_PACKAGES = ['services.js', 'extensions.js', 'monaco.js', 'assets.js', 'lifecycle.js', 'workbench.js', 'missing-services.js', 'l10n.js']
/**
* Files to expose in the editor-api package (just exporting everyting from the corresponding VSCode file)
* for compability with libraries that import internal monaco-editor modules
Expand Down
2 changes: 1 addition & 1 deletion rollup/rollup.language-packs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export default rollup.defineConfig([
return `
import { registerLocalization } from 'vscode/l10n'
import content from '${path.resolve(id, mainTranslation.path)}'
registerLocalization('${mainLocalization.languageId}', content, {
registerLocalization('${packageJson.publisher}.${packageJson.name}', '${mainLocalization.languageId}', content, {
${Object.entries(translationAssets).map(([id, assetRef]) => ` '${id}': new URL(import.meta.ROLLUP_FILE_URL_${assetRef}, import.meta.url).href`).join(',\n')}
})
`
Expand Down
22 changes: 20 additions & 2 deletions src/l10n.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,39 @@
import { setLocale, isInitialized } from 'vs/nls'

const extensionTranslationsUri: Record<string, Record<string, string>> = {}
let currentLocaleExtensionId: string | undefined
let availableLocales: Set<string> = new Set()

function registerLocalization (language: string, main: Record<string, Record<string, string>>, extensionTranslationsUris: Record<string, string>): void {
function setAvailableLocales (locales: Set<string>): void {
availableLocales = locales
}

function isLocaleAvailable (locale: string): boolean {
return availableLocales.has(locale)
}

function registerLocalization (extensionId: string, language: string, main: Record<string, Record<string, string>>, extensionTranslationsUris: Record<string, string>): void {
if (isInitialized()) {
console.error('Some parts of VSCode are already initialized, make sure the language pack is loaded before anything else or some translations will be missing')
}
setLocale(language, main)

extensionTranslationsUri[language] = extensionTranslationsUris
currentLocaleExtensionId = extensionId
}

function getBuiltInExtensionTranslationsUris (language: string): Record<string, string> | undefined {
return extensionTranslationsUri[language]
}

function getExtensionIdProvidingCurrentLocale (): string | undefined {
return currentLocaleExtensionId
}

export {
registerLocalization,
getBuiltInExtensionTranslationsUris
getBuiltInExtensionTranslationsUris,
getExtensionIdProvidingCurrentLocale,
setAvailableLocales,
isLocaleAvailable
}
14 changes: 7 additions & 7 deletions src/missing-services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,9 @@ import { IAuthenticationAccessService } from 'vs/workbench/services/authenticati
import { IAuthenticationUsageService } from 'vs/workbench/services/authentication/browser/authenticationUsageService'
import { ICustomEditorLabelService } from 'vs/workbench/services/editor/common/customEditorLabelService'
import { IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService'
import { getBuiltInExtensionTranslationsUris } from './l10n'
import { createInstanceCapabilityEventMultiplexer } from 'vs/workbench/contrib/terminal/browser/terminalEvents'
import { TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities'
import { getBuiltInExtensionTranslationsUris, getExtensionIdProvidingCurrentLocale } from './l10n'
import { unsupported } from './tools'

registerSingleton(ILoggerService, class NullLoggerService extends AbstractLoggerService {
Expand Down Expand Up @@ -1656,10 +1658,8 @@ registerSingleton(ITerminalService, class TerminalService implements ITerminalSe
onAnyInstanceProcessIdReady = Event.None
onAnyInstanceSelectionChange = Event.None
onAnyInstanceTitleChange = Event.None
createOnInstanceEvent = unsupported
createOnInstanceCapabilityEvent = unsupported
onInstanceEvent = unsupported
onInstanceCapabilityEvent = unsupported
createOnInstanceEvent = () => Event.None
createOnInstanceCapabilityEvent = <T extends TerminalCapability, K>(capabilityId: T) => createInstanceCapabilityEventMultiplexer<T, K>([], Event.None, Event.None, capabilityId, () => Event.None)
createDetachedTerminal = unsupported

onDidChangeSelection = Event.None
Expand Down Expand Up @@ -2466,8 +2466,8 @@ registerSingleton(IInteractiveDocumentService, class InteractiveDocumentService

registerSingleton(IActiveLanguagePackService, class ActiveLanguagePackService implements IActiveLanguagePackService {
readonly _serviceBrand: undefined
getExtensionIdProvidingCurrentLocale () {
return Promise.resolve(undefined)
async getExtensionIdProvidingCurrentLocale (): Promise<string | undefined> {
return getExtensionIdProvidingCurrentLocale()
}
}, InstantiationType.Eager)

Expand Down
16 changes: 14 additions & 2 deletions src/service-override/extensionGallery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'
import { IExtensionGalleryService, IExtensionManagementService, IExtensionTipsService, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'
import { GlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService'
import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions'
import { IExtension as IContribExtension, IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions'
import { getLocale } from 'vs/platform/languagePacks/common/languagePacks'
import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/browser/extensionsWorkbenchService'
import { IExtensionManagementServerService, IWebExtensionsScannerService, IWorkbenchExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'
import { ExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagementServerService'
Expand Down Expand Up @@ -33,6 +34,7 @@ import { IExtensionFeaturesManagementService } from 'vs/workbench/services/exten
import { ExtensionFeaturesManagementService } from 'vs/workbench/services/extensionManagement/common/extensionFeaturesManagemetService'
import { registerAssets } from '../assets'
import { getExtensionManifests } from '../extensions'
import { isLocaleAvailable } from '../l10n'
import 'vs/workbench/contrib/extensions/browser/extensions.contribution'
import 'vs/workbench/contrib/extensions/browser/extensions.web.contribution'

Expand Down Expand Up @@ -78,6 +80,16 @@ class CustomBuiltinExtensionsScannerService implements IBuiltinExtensionsScanner
}
}

class ExtensionsWorkbenchServiceOverride extends ExtensionsWorkbenchService {
override canSetLanguage (extension: IContribExtension): boolean {
if (super.canSetLanguage(extension)) {
const locale = getLocale(extension.gallery!)!
return isLocaleAvailable(locale)
}
return false
}
}

export interface ExtensionGalleryOptions {
/**
* Whether we should only allow for web extensions to be installed, this is generally
Expand All @@ -90,7 +102,7 @@ export default function getServiceOverride (options: ExtensionGalleryOptions = {
return {
[IExtensionGalleryService.toString()]: new SyncDescriptor(ExtensionGalleryService, [], true),
[IGlobalExtensionEnablementService.toString()]: new SyncDescriptor(GlobalExtensionEnablementService, [], true),
[IExtensionsWorkbenchService.toString()]: new SyncDescriptor(ExtensionsWorkbenchService, [], true),
[IExtensionsWorkbenchService.toString()]: new SyncDescriptor(ExtensionsWorkbenchServiceOverride, [], true),
[IExtensionManagementServerService.toString()]: new SyncDescriptor(ExtensionManagementServerServiceOverride, [options.webOnly], true),
[IExtensionRecommendationsService.toString()]: new SyncDescriptor(ExtensionRecommendationsService, [], true),
[IExtensionRecommendationNotificationService.toString()]: new SyncDescriptor(ExtensionRecommendationNotificationService, [], true),
Expand Down
Loading

1 comment on commit 689fcbc

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.