@voerkai18n/utils
Version:
utils for voerkai18n
113 lines (101 loc) • 3.35 kB
text/typescript
import { pick } from "flex-tools/object/pick";
import { encodeRegExp } from "./encodeRegExp";
import { escapeRegex } from "./escapeRegex";
export type ParagraphNode = {
id? : string
message : string
vars? : string
scope? : string
options?: string
rang : { start: number, end: number }
file? : string
[key : string]: any
}
export type ExtractParagraphsOptions = {
language? : string
namespaces? : Record<string,string>
file? : string
tComponentNames?: string[]
}
const attrsRegex = /(?<name>\w+)\s*=\s*(["'])(?<value>.*?)\2/gm
function parseTranslateAttrs(attrs:string):Record<string,any> {
let result
let attrsMap:Record<string,any> = {}
while ((result = attrsRegex.exec(attrs)) !== null) {
const { name,value } = result.groups || {}
if(name && value){
attrsMap[name] = value
}
}
return attrsMap
}
// /<Translate\s*[^>]*(id\s*=\s*(['"])(\w+)\2)?[^>]*?(?<![\/])>(?<text>[\s\S]*?)<\/Translate>/gm
const paragraphExtractors = [
/<(__T_COMPONENT__)\s*(?<attrs>[^>]*)(?<![\/])>(?<text>[\s\S]*?)<\/\1>/
]
function getParagraphExtractors(options:{tComponentNames:string[]}){
const { tComponentNames=['Translate','v-translate'] } = options
return paragraphExtractors.map(regex=>{
return new RegExp(encodeRegExp(regex,{
"__T_COMPONENT__" : tComponentNames.map(n=>escapeRegex(n)).join("|")
}),"gm")
})
}
/**
* 解释段落
*/
export function parseParagraphsByRegex(code:string,options:ExtractParagraphsOptions){
const { file } = options
const { tComponentNames } = Object.assign({
tComponentNames: ['Translate','v-translate']
},options)
const paragraphExtractors = getParagraphExtractors({ tComponentNames })
let result
let paragraphs:ParagraphNode[] = []
for(let regex of paragraphExtractors){
while ((result = regex.exec(code)) !== null) {
// 这对于避免零宽度匹配的无限循环是必要的
if (result.index === regex.lastIndex) {
regex.lastIndex++;
}
const text = result.groups?.text
const attrs = parseTranslateAttrs(result.groups?.attrs || '')
if(text){
paragraphs.push({
message:text,
rang:{
start: result.index,
end: result.index + result[0].length
},
file,
...pick(attrs,[
'id',
'vars',
'scope',
'options',
'tag',
'style',
'class',
'className'
])
})
}
}
}
return paragraphs
}
/**
*
* 提取段落
*
* <Translate>
* 段落内容
* </Translate>
*
* @param code
*/
export function extractParagraphs(code:string,options?:ExtractParagraphsOptions):ParagraphNode[]{
const opts = Object.assign({},options) as Required<ExtractParagraphsOptions>
const paragraphs:ParagraphNode[] = parseParagraphsByRegex(code,opts)
return paragraphs
}