✨ feat(vscode): 代码阅读关键字按语境翻译
This commit is contained in:
1 parent
72d33032f0
commit
d134837c17
5 files changed
+155
-19
No files matched your search
@@ -1,7 +1,16 @@
|
||||
import type { CodeBlock, Node, Segment, SourceSpan, TokenRole, Translator } from '../contract'
|
||||
|
||||
/** 按父节点类型区分译法的关键字,例如 Python 的 in:for 头部里「取自」,比较里「在」。 */
|
||||
export interface ContextualWord { zh: string, byParent: Record<string, string> }
|
||||
/** 按所在语法节点区分译法的关键字,例如 Python 的 else:if 后「否则」,for / while 后「未中断时」。 */
|
||||
export interface ContextualWord {
|
||||
/** 没有匹配的语境时用的译法。 */
|
||||
zh: string
|
||||
/**
|
||||
* 语境 → 译法。语境是关键字节点往上的节点类型链,外层在前、用 ` > ` 连接:
|
||||
* `raise_statement` 指父节点,`for_statement > else_clause` 指父节点 else_clause 且祖父节点 for_statement。
|
||||
* 同时匹配多条时取最长的那条。
|
||||
*/
|
||||
byContext: Record<string, string>
|
||||
}
|
||||
|
||||
/** 一种语言的中文直译表。引擎只替换表里的三类东西,其余原样照抄。 */
|
||||
export interface ZhTable {
|
||||
@@ -10,7 +19,7 @@ export interface ZhTable {
|
||||
languageIds: string[]
|
||||
/** 未翻译的词按源码着色的词性上色;关键字译文的词性也取它。 */
|
||||
tokenRole: (leaf: Node) => TokenRole
|
||||
/** 关键字:按语法树里匿名节点的类型查(Python 的 `not in` 这类组合关键字本身也是一个匿名节点)。 */
|
||||
/** 关键字:按语法树里匿名节点的类型查(Python 的 `not in` 这类组合关键字本身也是一个匿名节点);随所在语法节点换译法的写成 ContextualWord。 */
|
||||
keywords: Record<string, string | ContextualWord>
|
||||
/** 字面量关键字:具名的叶子节点(true / None …),按节点类型查。 */
|
||||
literals: Record<string, string>
|
||||
@@ -38,6 +47,7 @@ interface Token {
|
||||
raw: string
|
||||
}
|
||||
|
||||
const CONTEXT_SEPARATOR = ' > '
|
||||
const CLOSING = new Set([')', ']', '}'])
|
||||
const HEADER_OPENERS = new Set(['{', ':'])
|
||||
|
||||
@@ -70,6 +80,22 @@ function oneLine(text: string): string {
|
||||
export function createZhTemplateTranslator(table: ZhTable): Translator {
|
||||
const operatorParents = new Set(table.operatorParents)
|
||||
const stringNodes = new Set(table.stringNodes)
|
||||
const contextDepth = Math.max(0, ...Object.values(table.keywords).flatMap(word =>
|
||||
typeof word === 'string' ? [] : Object.keys(word.byContext).map(context => context.split(CONTEXT_SEPARATOR).length)))
|
||||
|
||||
/** 从父节点往上逐层拼出语境去查,更长(更具体)的匹配覆盖更短的。 */
|
||||
function keywordText(word: string | ContextualWord, node: Node): string {
|
||||
if (typeof word === 'string')
|
||||
return word
|
||||
let text = word.zh
|
||||
let context = ''
|
||||
let ancestor = node.parent
|
||||
for (let level = 0; ancestor && level < contextDepth; level++, ancestor = ancestor.parent) {
|
||||
context = context ? `${ancestor.type}${CONTEXT_SEPARATOR}${context}` : ancestor.type
|
||||
text = word.byContext[context] ?? text
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
/** 能整个换成中文的节点 → 译文和词性。 */
|
||||
function translateNode(node: Node): { text: string, role: TokenRole } | undefined {
|
||||
@@ -83,10 +109,8 @@ export function createZhTemplateTranslator(table: ZhTable): Translator {
|
||||
if (parent && operatorParents.has(parent.type) && table.operators[node.type])
|
||||
return { text: table.operators[node.type], role: 'operator' }
|
||||
const word = table.keywords[node.type]
|
||||
if (word !== undefined) {
|
||||
const text = typeof word === 'string' ? word : (parent && word.byParent[parent.type]) || word.zh
|
||||
return { text, role: table.tokenRole(firstLeaf(node)) }
|
||||
}
|
||||
if (word !== undefined)
|
||||
return { text: keywordText(word, node), role: table.tokenRole(firstLeaf(node)) }
|
||||
return undefined
|
||||
}
|
||||
if (node.childCount === 0 && table.literals[node.type])
|
||||
|
||||
Reference in new issue
Block a user