Skip to content

Commit

Permalink
fix: optimize localization
Browse files Browse the repository at this point in the history
replace localization keys by indexes
  • Loading branch information
Loïc Mangeonjean authored and CGNonofr committed Apr 30, 2024
1 parent 8e190f1 commit 127e580
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 14 deletions.
47 changes: 44 additions & 3 deletions rollup/rollup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ function isCallPure (file: string, functionName: string, node: recast.types.name
return PURE_OR_TO_REMOVE_FUNCTIONS.has(functionName)
}

const moduleNlsKeys: Record<string, string[]> = {}

function transformVSCodeCode (id: string, code: string) {
// HACK: assign typescript decorator result to a decorated class field so rollup doesn't remove them
// before:
Expand Down Expand Up @@ -206,7 +208,43 @@ function transformVSCodeCode (id: string, code: string) {
const node = path.node
const name = node.callee.type === 'MemberExpression' || node.callee.type === 'Identifier' ? getMemberExpressionPath(node.callee) : null

if (node.callee.type === 'MemberExpression') {
if (name != null && (name.endsWith('localizeWithPath') || name.endsWith('localize2WithPath'))) {
const translationPath = nodePath.relative(id.startsWith(OVERRIDE_PATH) ? OVERRIDE_PATH : VSCODE_SRC_DIR, id).slice(0, -3)
let localizationKey: string
if (path.node.arguments[1]?.type === 'StringLiteral') {
localizationKey = path.node.arguments[1].value
} else if (path.node.arguments[1]?.type === 'ObjectExpression') {
const properties = path.node.arguments[1].properties
const keyProperty = properties.find<recast.types.namedTypes.ObjectProperty>((prop): prop is recast.types.namedTypes.ObjectProperty => prop.type === 'ObjectProperty' && prop.key.type === 'Identifier' && prop.key.name === 'key')
if (keyProperty == null) {
throw new Error('No key property')
}
if (keyProperty.value.type !== 'StringLiteral') {
throw new Error('Key property is not literal')
}
localizationKey = keyProperty.value.value
} else if (path.node.arguments[1]?.type === 'TemplateLiteral' && path.node.arguments[1].expressions.length === 0 && path.node.arguments[1].quasis.length === 1) {
localizationKey = path.node.arguments[1].quasis[0]!.value.raw
} else {
throw new Error('Unable to extract translation key')
}
let nlsKeys = moduleNlsKeys[translationPath]
if (nlsKeys == null) {
nlsKeys = []
moduleNlsKeys[translationPath] = nlsKeys
}

let index = nlsKeys.indexOf(localizationKey)
if (index < 0) {
index = nlsKeys.length
nlsKeys.push(localizationKey)
}
path.replace(recast.types.builders.callExpression(
path.node.callee,
[path.node.arguments[0]!, recast.types.builders.numericLiteral(index), ...path.node.arguments.slice(2)]
))
transformed = true
} else if (node.callee.type === 'MemberExpression') {
if (node.callee.property.type === 'Identifier') {
const names: string[] = [node.callee.property.name]
if (name != null) {
Expand Down Expand Up @@ -422,10 +460,10 @@ export default (args: Record<string, string>): rollup.RollupOptions[] => {
return undefined
},
async load (id) {
if (!id.startsWith(VSCODE_SRC_DIR)) {
if (!id.startsWith(VSCODE_SRC_DIR) && !id.startsWith(OVERRIDE_PATH)) {
return undefined
}
if (!id.endsWith('.js')) {
if (!id.endsWith('.js') && !id.endsWith('.ts')) {
return undefined
}

Expand All @@ -434,6 +472,9 @@ export default (args: Record<string, string>): rollup.RollupOptions[] => {
},
transform (code) {
return code.replaceAll("'./keyboardLayouts/layout.contribution.' + platform", "'./keyboardLayouts/layout.contribution.' + platform + '.js'")
},
async writeBundle () {
await fs.promises.writeFile(nodePath.resolve(DIST_DIR, 'nls.metadata.json'), JSON.stringify(moduleNlsKeys, null, 2))
}
},
{
Expand Down
22 changes: 11 additions & 11 deletions rollup/rollup.language-packs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import * as rollup from 'rollup'
import { IExtensionManifest } from 'vs/platform/extensions/common/extensions'
import { dataToEsm } from '@rollup/pluginutils'
import { PackageJson } from 'type-fest'
import glob from 'fast-glob'
import * as fs from 'fs'
import * as path from 'path'
import { fileURLToPath } from 'url'
Expand All @@ -22,12 +21,7 @@ const locExtensions = fs.readdirSync(LOC_PATH, { withFileTypes: true })
.filter(f => f.isDirectory() && fs.existsSync(path.resolve(LOC_PATH, f.name, 'package.json')))
.map(f => f.name)

const vscodeModules = (await glob('**/vscode/src/**/*.js', {
cwd: DIST_DIR,
onlyFiles: true
})).map(fileName => /vscode\/src\/(.*).js$/.exec(fileName)![1]!)

const usedModules = new Set<string>([...vscodeModules, 'vs/workbench/browser/web.main'])
const nlsMetadata: Record<string, string[]> = JSON.parse((await fs.promises.readFile(path.resolve(DIST_DIR, 'nls.metadata.json'))).toString())

export default rollup.defineConfig([
...locExtensions.map(name => (<rollup.RollupOptions>{
Expand Down Expand Up @@ -92,12 +86,18 @@ ${Object.entries(translationAssets).map(([id, assetRef]) => ` '${id}': new URL(
transform (code, id) {
if (!id.endsWith('.json')) return null

const parsed = JSON.parse(code).contents
// remove keys that we don't use
const filtered = Object.fromEntries(Object.entries(parsed).filter(([key]) => usedModules.has(key)))
const parsed: Record<string, Record<string, string>> = JSON.parse(code).contents

const encoded = Object.fromEntries(Object.entries(nlsMetadata).map(([moduleId, keys]) => {
const values = parsed[moduleId] ?? {}
return [
moduleId,
keys.map(key => values[key])
]
}))

return {
code: dataToEsm(filtered, {
code: dataToEsm(encoded, {
preferConst: true
}),
map: { mappings: '' }
Expand Down

0 comments on commit 127e580

Please sign in to comment.