更新tools
This commit is contained in:
parent
54546276ab
commit
7494bad78b
@ -1,26 +1,51 @@
|
||||
import { t,languages,scope } from "./languages/index.js"
|
||||
|
||||
VoerkaI18n.on((language)=>{
|
||||
console.log("切换到语言:",language)
|
||||
})
|
||||
import messageIds from "./idMap.js"
|
||||
import { translate,I18nManager } from "@voerkai18n/runtime"
|
||||
import defaultMessages from "./cn.js"
|
||||
import scopeSettings from "./settings.js"
|
||||
|
||||
async function output(){
|
||||
console.log(t("用户名或密码错误"))
|
||||
console.log(t('请输入用户名:'))
|
||||
console.log(t("请输入密码:"))
|
||||
console.log(t("欢迎您: {}","张三丰"))
|
||||
console.log("----------------")
|
||||
await VoerkaI18n.change("en")
|
||||
console.log(t("用户名或密码错误"))
|
||||
console.log(t('请输入用户名:'))
|
||||
console.log(t("请输入密码:"))
|
||||
console.log(t("欢迎您: {}","tom"))
|
||||
console.log("----------------")
|
||||
await VoerkaI18n.change("cn")
|
||||
console.log(t("用户名或密码错误"))
|
||||
console.log(t('请输入用户名:'))
|
||||
console.log(t("请输入密码:"))
|
||||
console.log(t("欢迎您: {}","tom"))
|
||||
|
||||
// 自动创建全局VoerkaI18n实例
|
||||
if(!globalThis.VoerkaI18n){
|
||||
globalThis.VoerkaI18n = new I18nManager(scopeSettings)
|
||||
}
|
||||
|
||||
output().then(()=>{})
|
||||
let scope = {
|
||||
defaultLanguage: "cn", // 默认语言名称
|
||||
default: defaultMessages, // 默认语言包
|
||||
messages : defaultMessages, // 当前语言包
|
||||
idMap:messageIds, // 消息id映射列表
|
||||
formatters:{}, // 当前作用域的格式化函数列表
|
||||
loaders:{}, // 异步加载语言文件的函数列表
|
||||
global:{}, // 引用全局VoerkaI18n配置,注册后自动引用
|
||||
// 主要用来缓存格式化器的引用,当使用格式化器时可以直接引用,避免检索
|
||||
$cache:{
|
||||
activeLanguage:null,
|
||||
typedFormatters:{},
|
||||
formatters:{},
|
||||
}
|
||||
}
|
||||
|
||||
let supportedlanguages = {}
|
||||
|
||||
|
||||
scope.loaders["en"] = ()=>import("./en.js")
|
||||
|
||||
|
||||
const t = translate.bind(scope)
|
||||
const languages = [
|
||||
{
|
||||
"name": "cn",
|
||||
"title": "cn"
|
||||
},
|
||||
{
|
||||
"name": "en",
|
||||
"title": "en"
|
||||
}
|
||||
]
|
||||
// 注册当前作用域到全局VoerkaI18n实例
|
||||
VoerkaI18n.register(scope)
|
||||
|
||||
|
||||
export { t, languages,scope }
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
{
|
||||
"type": "module"
|
||||
"type": "commonjs",
|
||||
"license": "MIT"
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
|
||||
|
||||
const compile = require('@voerkai18n/tools/compile');
|
||||
const compile = require('@voerkai18n/tools/compile.command');
|
||||
const path = require("path")
|
||||
|
||||
|
||||
|
2
packages/tools/.env
Normal file
2
packages/tools/.env
Normal file
@ -0,0 +1,2 @@
|
||||
# 命令行工具使用的语言
|
||||
language=en
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* 转译源码中的t翻译函数的翻译内容转换为唯一的id值
|
||||
*
|
||||
* - 将源文件中的t("xxxxx")转码成t(hash(xxxxx))
|
||||
* - 将源文件中的t("xxxxx")转码成t("id")
|
||||
* - 自动导入languages/index.js中的翻译函数t
|
||||
*
|
||||
* 使用方法:
|
||||
|
@ -31,25 +31,20 @@ const { importModule,findModuleType } = require("./utils")
|
||||
const fs = require("fs")
|
||||
const logger = createLogger()
|
||||
const artTemplate = require("art-template")
|
||||
|
||||
const { t } = require("./languages")
|
||||
function normalizeCompileOptions(opts={}) {
|
||||
let options = Object.assign({
|
||||
input:null, // 指定要编译的文件夹,即extract输出的语言文件夹
|
||||
output:null, // 指定编译后的语言文件夹,如果没有指定,则使用input目录
|
||||
moduleType:"auto" // 指定编译后的语言文件的模块类型,取值common,cjs,esm,es
|
||||
}, opts)
|
||||
if(options.moduleType==="es") options.moduleType = "esm"
|
||||
if(options.moduleType==="cjs") options.moduleType = "commonjs"
|
||||
if(!["commonjs","cjs","esm","es"].includes(options.moduleType)) options.moduleType = "esm"
|
||||
if(!["auto","commonjs","cjs","esm","es"].includes(options.moduleType)) options.moduleType = "esm"
|
||||
return options;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
module.exports =async function compile(langFolder,opts={}){
|
||||
const options = normalizeCompileOptions(opts);
|
||||
const { output,moduleType } = options;
|
||||
let { moduleType } = options;
|
||||
|
||||
if(moduleType==="auto"){
|
||||
moduleType = findModuleType(langFolder)
|
||||
@ -63,7 +58,7 @@ module.exports =async function compile(langFolder,opts={}){
|
||||
const langSettings = module.default;
|
||||
let { languages,defaultLanguage,activeLanguage,namespaces } = langSettings
|
||||
|
||||
logger.log("支持的语言\t: {}",languages.map(item=>`${item.title}(${item.name})`))
|
||||
logger.log(t("支持的语言\t: {}",languages.map(item=>`${item.title}(${item.name})`).join(",")))
|
||||
logger.log("默认语言\t: {}",defaultLanguage)
|
||||
logger.log("激活语言\t: {}",activeLanguage)
|
||||
logger.log("名称空间\t: {}",Object.keys(namespaces).join(","))
|
||||
@ -87,7 +82,7 @@ module.exports =async function compile(langFolder,opts={}){
|
||||
logger.log("读取语言文件{}失败:{}",file,e.message)
|
||||
}
|
||||
})
|
||||
logger.log(" - 合成语言包文本,共{}条",Object.keys(messages).length)
|
||||
logger.log(" - 共合成{}条语言包文本",Object.keys(messages).length)
|
||||
|
||||
// 2. 为每一个文本内容生成一个唯一的id
|
||||
let messageIds = {}
|
||||
@ -158,12 +153,12 @@ module.exports =async function compile(langFolder,opts={}){
|
||||
let packageJson = {}
|
||||
if(moduleType==="esm"){
|
||||
packageJson = {
|
||||
version:"1.0.0",
|
||||
license:"MIT",
|
||||
type:"module",
|
||||
}
|
||||
}else{
|
||||
packageJson = {
|
||||
version:"1.0.0",
|
||||
license:"MIT",
|
||||
}
|
||||
}
|
||||
fs.writeFileSync(packageJsonFile,JSON.stringify(packageJson,null,4))
|
@ -2,6 +2,7 @@ const { findModuleType } = require("./utils")
|
||||
const path = require("path")
|
||||
const fs = require("fs")
|
||||
const gulp = require("gulp")
|
||||
const extractor = require("./extract.plugin")
|
||||
const createLogger = require("logsets")
|
||||
const logger = createLogger()
|
||||
|
||||
@ -13,13 +14,11 @@ module.exports = function(targetPath,options={}){
|
||||
const folders = filetypes.map(ftype=>{
|
||||
if(ftype.startsWith(".")) ftype = "*"+ftype
|
||||
if(!ftype.startsWith("*.")) ftype = "*."+ftype
|
||||
return path.join(targetPath,ftype)
|
||||
return path.join(targetPath,"**",ftype)
|
||||
})
|
||||
folders.push(`!${path.join(targetPath,"languages")}`)
|
||||
folders.push(`!${path.join(targetPath,"node_modules")}`)
|
||||
folders.push(`!${path.join(targetPath,"languages","**")}`)
|
||||
folders.push(`!${path.join(targetPath,"node_modules","**")}`)
|
||||
folders.push(`!${path.join(targetPath,"**","node_modules","**")}`)
|
||||
// 排除文件夹
|
||||
console.log("exclude",exclude)
|
||||
if(!Array.isArray(exclude) && exclude){
|
||||
exclude = exclude.split(",")
|
||||
}
|
||||
@ -28,9 +27,17 @@ module.exports = function(targetPath,options={}){
|
||||
folders.push(`!${path.join(targetPath,folder)}`)
|
||||
})
|
||||
}
|
||||
|
||||
console.log(folders)
|
||||
|
||||
|
||||
//gulp.src(path.join(targetPath,"**/*.json"))
|
||||
if(!fs.existsSync(targetPath)){
|
||||
logger.log("目标文件夹<{}>不存在",targetPath)
|
||||
return
|
||||
}
|
||||
if(options.debug){
|
||||
logger.log("扫描提取范围:")
|
||||
logger.format(folders)
|
||||
}
|
||||
|
||||
options.outputPath = path.join(targetPath,"languages")
|
||||
gulp.src(folders)
|
||||
.pipe(extractor(options))
|
||||
.pipe(gulp.dest(options.outputPath))
|
||||
}
|
@ -12,8 +12,10 @@ const fs = require('fs')
|
||||
const readJson = require("readjson")
|
||||
const createLogger = require("logsets")
|
||||
const { replaceInterpolateVars,getDataTypeName } = require("@voerkai18n/runtime")
|
||||
const { findModuleType } = require("./utils")
|
||||
const { findModuleType,createPackageJsonFile } = require("./utils")
|
||||
const logger = createLogger()
|
||||
const { t } = require("./languages")
|
||||
|
||||
|
||||
// 捕获翻译文本的默认正则表达式
|
||||
const DefaultTranslateExtractor = String.raw`\b{funcName}\(\s*("|'){1}(?:((?<namespace>\w+)::))?(?<text>.*?)(((\1\s*\)){1})|((\1){1}\s*(,(\w|\d|(?:\{.*\})|(?:\[.*\])|([\"\'\(].*[\"\'\)]))*)*\s*\)))`
|
||||
@ -349,13 +351,14 @@ function updateLanguageFile(fromTexts,toLangFile,options){
|
||||
|
||||
module.exports = function(options={}){
|
||||
options = normalizeLanguageOptions(options)
|
||||
let {debug,output:{ path:outputPath, updateMode },languages} = options
|
||||
|
||||
logger.log("Supported languages\t: {}",options.languages.map(item=>`${item.title}(${item.name})`))
|
||||
logger.log("Default language\t: {}",options.defaultLanguage)
|
||||
logger.log("Active language\t\t: {}",options.activeLanguage)
|
||||
logger.log("Language namespaces\t: {}",Object.keys(options.namespaces).join(","))
|
||||
let {debug,outputPath, updateMode,languages} = options
|
||||
|
||||
logger.log(t("支持的语言\t: {}"),options.languages.map(item=>`${item.title}(${item.name})`).join(","))
|
||||
logger.log("默认语言\t: {}",options.defaultLanguage)
|
||||
logger.log("激活语言\t: {}",options.activeLanguage)
|
||||
logger.log("名称空间\t: {}",Object.keys(options.namespaces).join(","))
|
||||
logger.log("")
|
||||
logger
|
||||
// 保存提交提取的文本 = {}
|
||||
let results = {}
|
||||
let fileCount=0 // 文件总数
|
||||
@ -375,21 +378,24 @@ module.exports = function(options={}){
|
||||
fileCount++
|
||||
if(debug){
|
||||
const textCount = Object.values(texts).reduce((sum,item)=>sum+Object.keys(item).length,0)
|
||||
logger.log("Extract <{}>, found [{}] namespaces and {} messages.",file.relative,Object.keys(texts).join(),textCount)
|
||||
logger.log("提取<{}>, 发现 [{}] 名称空间,{} 条信息。",file.relative,Object.keys(texts).join(),textCount)
|
||||
}
|
||||
}catch(err){
|
||||
logger.log("Error while extract messages from <{}> : {}",file.relative,err.message)
|
||||
logger.log("从<{}>提取信息时出错 : {}",file.relative,err.message)
|
||||
}
|
||||
|
||||
callback()
|
||||
},function(callback){
|
||||
logger.log("")
|
||||
logger.log("Extracting finished.")
|
||||
logger.log(" - Total of files\t: {}",fileCount)
|
||||
logger.log(" - Output location\t: {}",outputPath)
|
||||
logger.log("翻译信息提取完成。")
|
||||
logger.log(" - 文件总数\t: {}",fileCount)
|
||||
logger.log(" - 输出路径\t: {}",outputPath)
|
||||
const translatesPath = path.join(outputPath,"translates")
|
||||
if(!fs.existsSync(outputPath)) fs.mkdirSync(outputPath)
|
||||
if(!fs.existsSync(translatesPath)) fs.mkdirSync(translatesPath)
|
||||
if(!("default" in results)){
|
||||
results["default"] = {}
|
||||
}
|
||||
// 每个名称空间对应一个文件
|
||||
for(let [namespace,texts] of Object.entries(results)){
|
||||
const langFile = path.join(outputPath,"translates",`${namespace}.json`)
|
||||
@ -397,10 +403,10 @@ module.exports = function(options={}){
|
||||
const langTexts = {}
|
||||
if(isExists){
|
||||
updateLanguageFile(texts,langFile,options)
|
||||
logger.log(" Update language file : {}",path.relative(outputPath,langFile))
|
||||
logger.log(" √ 更新语言文件 : {}",path.relative(outputPath,langFile))
|
||||
}else{
|
||||
fs.writeFileSync(langFile,JSON.stringify(texts,null,4))
|
||||
logger.log(" Save language file : {}",path.relative(outputPath,langFile))
|
||||
logger.log(" √ 保存语言文件 : {}",path.relative(outputPath,langFile))
|
||||
}
|
||||
}
|
||||
// 生成语言配置文件 settings.js , 仅当不存在时才生成
|
||||
@ -413,13 +419,20 @@ module.exports = function(options={}){
|
||||
namespaces : options.namespaces
|
||||
}
|
||||
fs.writeFileSync(settingsFile,`module.exports = ${JSON.stringify(settings,null,4)}`)
|
||||
logger.log(" - Generate settings of language : {}",settingsFile)
|
||||
logger.log(" - 生成语言配置文件: {}",settingsFile)
|
||||
}else{
|
||||
logger.log(" - Settings of language already exists : {}",settingsFile)
|
||||
logger.log(" - 已更新语言配置文件: {}",settingsFile)
|
||||
}
|
||||
|
||||
|
||||
// 生成package.json
|
||||
const packageJsonFile = path.join(outputPath,"package.json")
|
||||
fs.writeFileSync(packageJsonFile,`${JSON.stringify({type:"commonjs"},null,4)}`)
|
||||
createPackageJsonFile(outputPath)
|
||||
|
||||
logger.log("下一步:")
|
||||
logger.log(" - 运行<{}>编译语言包","voerkai18n compile")
|
||||
logger.log(" - 在源码中导入编译后的语言包[{}]","import './languages'")
|
||||
|
||||
|
||||
callback()
|
||||
});
|
||||
}
|
||||
|
@ -5,18 +5,18 @@ const fs = require("fs");
|
||||
const { importModule } = require('./utils');
|
||||
const deepmerge = require('deepmerge');
|
||||
const logger = createLogger()
|
||||
require('dotenv').config()
|
||||
|
||||
const { t, changeLanguage } = require("./languages")
|
||||
const program = new Command();
|
||||
|
||||
|
||||
program
|
||||
.option('-d, --debug', '输出调试信息')
|
||||
|
||||
program
|
||||
.command('init')
|
||||
.argument('[location]', '工程项目所在目录')
|
||||
.argument('[location]', t('工程项目所在目录'))
|
||||
.description('初始化项目国际化配置')
|
||||
.option('-d, --debug', '输出调试信息')
|
||||
.option('-r, --reset', '重新生成当前项目的语言配置')
|
||||
.option('-m, --moduleType [type]', '生成的js模块类型,默认esm',"esm")
|
||||
.option('-m, --moduleType [type]', '生成的js模块类型,取值auto,esm,cjs',"auto")
|
||||
.option('-lngs, --languages <languages...>', '支持的语言列表', ['cn','en'])
|
||||
.action((location,options) => {
|
||||
if(!location) {
|
||||
@ -25,8 +25,11 @@ program
|
||||
location = path.join(process.cwd(),location)
|
||||
}
|
||||
logger.log("工程目录:{}",location)
|
||||
//
|
||||
if(options.debug){
|
||||
logger.format(options,{compact:true})
|
||||
}
|
||||
const initializer = require("./init.command")
|
||||
options.debug=true
|
||||
initializer(location,options)
|
||||
});
|
||||
|
||||
@ -35,7 +38,7 @@ program
|
||||
.command('extract')
|
||||
.description('扫描并提取所有待翻译的字符串到<languages/translates>文件夹中')
|
||||
.option('-d, --debug', '输出调试信息')
|
||||
.option('-lngs, --languages', '支持的语言', 'cn,en,de,fr,es,it,jp')
|
||||
.option('-lngs, --languages', '支持的语言', 'cn,en')
|
||||
.option('-d, --defaultLanguage', '默认语言', 'cn')
|
||||
.option('-a, --activeLanguage', '激活语言', 'cn')
|
||||
.option('-ns, --namespaces', '翻译名称空间')
|
||||
@ -56,20 +59,51 @@ program
|
||||
logger.log("工程目录:{}",location)
|
||||
const langSettingsFile = path.join(location,"languages","settings.js")
|
||||
if(fs.existsSync(langSettingsFile)){
|
||||
logger.log("语言配置文件<{}>已存在.将优先使用此配置文件中参数来提取文本",langSettingsFile)
|
||||
logger.log("语言配置文件<{}>已存在,将优先使用此配置文件中参数来提取文本","./languages/settings.js")
|
||||
let lngOptions = (await importModule("file:///"+langSettingsFile)).default
|
||||
options.languages = lngOptions.languages
|
||||
options.defaultLanguage = lngOptions.defaultLanguage
|
||||
options.activeLanguage = lngOptions.activeLanguage
|
||||
options.namespaces = lngOptions.namespaces
|
||||
}
|
||||
|
||||
//
|
||||
if(options.debug){
|
||||
logger.format(options,{compact:true})
|
||||
}
|
||||
const extractor = require('./extract.command');
|
||||
extractor(location,options)
|
||||
});
|
||||
|
||||
|
||||
program
|
||||
.command('compile')
|
||||
.description('编译语言包文件<languages>文件夹中')
|
||||
.option('-d, --debug', '输出调试信息')
|
||||
.option('-m, --moduleType [types]', '输出模块类型,取值auto,esm,cjs', 'auto')
|
||||
.argument('[location]', t('工程项目所在目录'),"./")
|
||||
.hook("preAction",async (location,options) => {
|
||||
console.log("process.env.language",process.env.language)
|
||||
await changeLanguage("en")
|
||||
})
|
||||
.action(async (location,options) => {
|
||||
if(!location) {
|
||||
location = process.cwd()
|
||||
}else{
|
||||
location = path.join(process.cwd(),location)
|
||||
}
|
||||
const langFolder = path.join(location,"languages")
|
||||
if(!fs.existsSync(langFolder)){
|
||||
logger.error("语言包文件夹<{}>不存在",langFolder)
|
||||
return
|
||||
}
|
||||
if(options.debug){
|
||||
logger.format(options,{compact:true})
|
||||
}
|
||||
compile = require("./compile.command")
|
||||
compile(langFolder,options)
|
||||
});
|
||||
|
||||
program.parse(process.argv);
|
||||
|
||||
program.parseAsync(process.argv);
|
||||
|
||||
const options = program.opts();
|
@ -4,20 +4,20 @@
|
||||
*/
|
||||
|
||||
|
||||
const { findModuleType } = require("./utils")
|
||||
const { findModuleType,createPackageJsonFile } = require("./utils")
|
||||
const path = require("path")
|
||||
const fs = require("fs")
|
||||
const createLogger = require("logsets")
|
||||
const logger = createLogger()
|
||||
|
||||
|
||||
module.exports = function(targetPath,{debug = true,languages=["cn","en"],defaultLanguage="cn",activeLanguage="cn",moduleType = "auto",reset=false}={}){
|
||||
// 语言文件夹名称
|
||||
const langPath = "languages"
|
||||
// 查找当前项目的语言包类型路径
|
||||
const lngPath = path.join(targetPath,langPath)
|
||||
moduleType = createPackageJsonFile(lngPath,moduleType)
|
||||
|
||||
if(moduleType==="auto"){
|
||||
moduleType = findModuleType(targetPath)
|
||||
}
|
||||
if(moduleType==null) {
|
||||
if(debug){
|
||||
logger.log("找不到{}文件,{}只能在js项目工程中使用","package.json","voerkai18n")
|
||||
@ -26,7 +26,7 @@ module.exports = function(targetPath,{debug = true,languages=["cn","en"],default
|
||||
}
|
||||
}
|
||||
|
||||
const lngPath = path.join(targetPath,langPath)
|
||||
|
||||
if(!fs.existsSync(lngPath)){
|
||||
fs.mkdirSync(lngPath)
|
||||
if(debug) logger.log("创建语言包文件夹: {}",lngPath)
|
||||
@ -44,19 +44,17 @@ module.exports = function(targetPath,{debug = true,languages=["cn","en"],default
|
||||
activeLanguage,
|
||||
namespaces:{}
|
||||
}
|
||||
const packageJsonFile = path.join(targetPath,"languages","package.json")
|
||||
// 写入配置文件
|
||||
if(["esm","es"].includes(moduleType)){
|
||||
fs.writeFileSync(settingsFile,`export default ${JSON.stringify(settings,null,4)}`)
|
||||
fs.writeFileSync(packageJsonFile,JSON.stringify({type:"module"},null,4))
|
||||
}else{
|
||||
fs.writeFileSync(settingsFile,`module.exports = ${JSON.stringify(settings,null,4)}`)
|
||||
fs.writeFileSync(packageJsonFile,JSON.stringify({},null,4))
|
||||
}
|
||||
|
||||
if(debug) {
|
||||
logger.log("生成语言配置文件:{}","./languages/settings.js")
|
||||
logger.log("拟支持的语言:{}",settings.languages.map(l=>l.name).join(","))
|
||||
logger.log("下一步:")
|
||||
logger.log("初始化成功,下一步:")
|
||||
logger.log(" - 编辑{}确定拟支持的语言种类等参数","languages/settings.js")
|
||||
logger.log(" - 运行<{}>扫描提取要翻译的文本","voerkai18n extract")
|
||||
logger.log(" - 运行<{}>编译语言包","voerkai18n compile")
|
||||
|
4
packages/tools/languages/cn.js
Normal file
4
packages/tools/languages/cn.js
Normal file
@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
"1": "工程项目所在目录",
|
||||
"2": "支持的语言\\t: {}"
|
||||
}
|
4
packages/tools/languages/en.js
Normal file
4
packages/tools/languages/en.js
Normal file
@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
"1": "Project directory",
|
||||
"2": "Supported Languages\\t: {}"
|
||||
}
|
105
packages/tools/languages/formatters.js
Normal file
105
packages/tools/languages/formatters.js
Normal file
@ -0,0 +1,105 @@
|
||||
/**
|
||||
|
||||
格式化器用来对翻译文本内容中的插值变量进行格式化,
|
||||
比如将一个数字格式化为货币格式,或者将一个日期格式化为友好的日期格式。
|
||||
|
||||
- 以下定义了一些格式化器,在中文场景下,会启用这些格式化器。
|
||||
import dayjs from "dayjs";
|
||||
const formatters = {
|
||||
"*":{ // 在所有语言下生效的格式化器
|
||||
$types:{...}, // 只作用于特定数据类型的默认格式化器
|
||||
.... // 全局格式化器
|
||||
},
|
||||
cn:{
|
||||
// 只作用于特定数据类型的格式化器
|
||||
$types:{
|
||||
Date:(value)=>dayjs(value).format("YYYY年MM月DD日 HH:mm:ss"),
|
||||
},
|
||||
date:(value)=>dayjs(value).format("YYYY年MM月DD日")
|
||||
bjTime:(value)=>"北京时间"+ value,
|
||||
[格式化器名称]:(value)=>{...},
|
||||
[格式化器名称]:(value)=>{...},
|
||||
[格式化器名称]:(value)=>{...},
|
||||
},
|
||||
en:{
|
||||
$types:{
|
||||
Date:(value)=>dayjs(value).format("YYYY/MM/DD HH:mm:ss"), // 默认的格式化器
|
||||
},
|
||||
date:(value)=>dayjs(value).format("YYYY/MM/DD")
|
||||
bjTime:(value)=>"BeiJing "+ value,
|
||||
[格式化器名称]:(value)=>{...},
|
||||
[格式化器名称]:(value)=>{...},
|
||||
[格式化器名称]:(value)=>{...},
|
||||
}
|
||||
}
|
||||
- 在翻译函数中使用格式化器的方法,示例如下:
|
||||
|
||||
t("Now is { value | date | bjTime }",{value: new Date()})
|
||||
其等效于:
|
||||
t(`Now is ${bjTime(date(value))",{value: new Date()})
|
||||
由于value分别经过两个管道符转换,上一个管道符的输出作为下一个管道符的输入,可以多次使用管道符。
|
||||
|
||||
最终的输出结果:
|
||||
中文: "现在是北京时间2022年3月1日"
|
||||
英文: "Now is BeiJing 2022/03/01"
|
||||
|
||||
|
||||
*
|
||||
*/
|
||||
|
||||
const formatters = {
|
||||
"*":{ }, // 在所有语言下生效的格式化器
|
||||
$types:{ } // 在所有语言下只作用于特定数据类型的格式化器
|
||||
|
||||
cn:{
|
||||
$types:{
|
||||
"*":{
|
||||
|
||||
},
|
||||
Date:{
|
||||
|
||||
},
|
||||
Number:{
|
||||
|
||||
},
|
||||
String:{
|
||||
|
||||
},
|
||||
Array:{
|
||||
|
||||
},
|
||||
Object:{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
en:{
|
||||
$types:{
|
||||
"*":{
|
||||
|
||||
},
|
||||
Date:{
|
||||
|
||||
},
|
||||
Number:{
|
||||
|
||||
},
|
||||
String:{
|
||||
|
||||
},
|
||||
Array:{
|
||||
|
||||
},
|
||||
Object:{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.exports.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s = formatters
|
||||
|
||||
|
4
packages/tools/languages/idMap.js
Normal file
4
packages/tools/languages/idMap.js
Normal file
@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
"工程项目所在目录": 1,
|
||||
"支持的语言\\t: {}": 2
|
||||
}
|
57
packages/tools/languages/index.js
Normal file
57
packages/tools/languages/index.js
Normal file
@ -0,0 +1,57 @@
|
||||
|
||||
const messageIds = require("./idMap")
|
||||
const { translate,I18nManager } = require("@voerkai18n/runtime")
|
||||
const defaultMessages = require("./cn.js")
|
||||
const scopeSettings = require("./settings.js")
|
||||
|
||||
|
||||
// 自动创建全局VoerkaI18n实例
|
||||
if(!globalThis.VoerkaI18n){
|
||||
globalThis.VoerkaI18n = new I18nManager(scopeSettings)
|
||||
}
|
||||
|
||||
let scope = {
|
||||
defaultLanguage: "cn", // 默认语言名称
|
||||
default: defaultMessages, // 默认语言包
|
||||
messages : defaultMessages, // 当前语言包
|
||||
idMap:messageIds, // 消息id映射列表
|
||||
formatters:{}, // 当前作用域的格式化函数列表
|
||||
loaders:{}, // 异步加载语言文件的函数列表
|
||||
global:{}, // 引用全局VoerkaI18n配置,注册后自动引用
|
||||
// 主要用来缓存格式化器的引用,当使用格式化器时可以直接引用,避免检索
|
||||
$cache:{
|
||||
activeLanguage:null,
|
||||
typedFormatters:{},
|
||||
formatters:{},
|
||||
}
|
||||
}
|
||||
|
||||
let supportedlanguages = {}
|
||||
|
||||
|
||||
scope.loaders["en"] = ()=>import("./en.js")
|
||||
|
||||
|
||||
const t = translate.bind(scope)
|
||||
const languages = [
|
||||
{
|
||||
"name": "cn",
|
||||
"title": "中文"
|
||||
},
|
||||
{
|
||||
"name": "en",
|
||||
"title": "英文"
|
||||
}
|
||||
]
|
||||
// 注册当前作用域到全局VoerkaI18n实例
|
||||
VoerkaI18n.register(scope)
|
||||
|
||||
|
||||
module.exports.languages = languages
|
||||
module.exports.scope = scope
|
||||
module.exports.t = t
|
||||
module.exports.changeLanguage = VoerkaI18n.change.bind(VoerkaI18n)
|
||||
module.exports.addLanguageListener = VoerkaI18n.on.bind(VoerkaI18n)
|
||||
module.exports.removeLanguageListener = VoerkaI18n.off.bind(VoerkaI18n)
|
||||
module.exports.i18nManager = VoerkaI18n
|
||||
|
3
packages/tools/languages/package.json
Normal file
3
packages/tools/languages/package.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"license": "MIT"
|
||||
}
|
15
packages/tools/languages/settings.js
Normal file
15
packages/tools/languages/settings.js
Normal file
@ -0,0 +1,15 @@
|
||||
module.exports = {
|
||||
"languages": [
|
||||
{
|
||||
"name": "cn",
|
||||
"title": "中文"
|
||||
},
|
||||
{
|
||||
"name": "en",
|
||||
"title": "英文"
|
||||
}
|
||||
],
|
||||
"defaultLanguage": "cn",
|
||||
"activeLanguage": "cn",
|
||||
"namespaces": {}
|
||||
}
|
38
packages/tools/languages/translates/default.json
Normal file
38
packages/tools/languages/translates/default.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"工程项目所在目录": {
|
||||
"en": "Project directory",
|
||||
"$file": [
|
||||
"index.js"
|
||||
]
|
||||
},
|
||||
"支持的语言\\t: {}": {
|
||||
"en": "Supported Languages\\t: {}",
|
||||
"$file": [
|
||||
"extract.plugin.js"
|
||||
]
|
||||
},
|
||||
"xxxxx": {
|
||||
"en": "xxxxx",
|
||||
"$file": [
|
||||
"babel-plugin-voerkai18n.js"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"en": "id",
|
||||
"$file": [
|
||||
"babel-plugin-voerkai18n.js"
|
||||
]
|
||||
},
|
||||
"支持的语言\\t: {}\",languages.map(item=>`${item.title}(${item.name})`).join(": {
|
||||
"en": "支持的语言\\t: {}\",languages.map(item=>`${item.title}(${item.name})`).join(",
|
||||
"$file": [
|
||||
"compile.command.js"
|
||||
]
|
||||
},
|
||||
"Now is { value | date | bjTime }": {
|
||||
"en": "Now is { value | date | bjTime }",
|
||||
"$file": [
|
||||
"templates\\formatters.js"
|
||||
]
|
||||
}
|
||||
}
|
@ -4,7 +4,9 @@
|
||||
"description": "VoerkaI18n Tools",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"extract": "node ./index.js extract -d -e babel-plugin-voerkai18n.js,templates/**",
|
||||
"compile": "node ./index.js compile -d"
|
||||
},
|
||||
"author": "",
|
||||
"bin": {
|
||||
@ -18,9 +20,10 @@
|
||||
"art-template": "^4.13.2",
|
||||
"commander": "^9.0.0",
|
||||
"deepmerge": "^4.2.2",
|
||||
"dotenv": "^16.0.0",
|
||||
"glob": "^7.2.0",
|
||||
"gulp": "^4.0.2",
|
||||
"logsets": "^1.0.7",
|
||||
"logsets": "^1.0.8",
|
||||
"readjson": "^2.2.2",
|
||||
"through2": "^4.0.2",
|
||||
"vinyl": "^2.2.1"
|
||||
|
@ -5,7 +5,7 @@ import defaultMessages from "./{{defaultLanguage}}.js"
|
||||
import scopeSettings from "./settings.js"
|
||||
{{else}}
|
||||
const messageIds = require("./idMap")
|
||||
const { translate,i18n } = require("@voerkai18n/runtime")
|
||||
const { translate,I18nManager } = require("@voerkai18n/runtime")
|
||||
const defaultMessages = require("./{{defaultLanguage}}.js")
|
||||
const scopeSettings = require("./settings.js")
|
||||
{{/if}}
|
||||
@ -43,9 +43,13 @@ const languages = {{@ JSON.stringify(languages,null,4) }}
|
||||
VoerkaI18n.register(scope)
|
||||
|
||||
{{if moduleType === "esm"}}
|
||||
export { t, languages,scope }
|
||||
export { t, languages,scope,i18nManager:VoerkaI18n, changeLanguage:VoerkaI18n.change.bind(VoerkaI18n),addLanguageListener:VoerkaI18n.on.bind(VoerkaI18n),removeLanguageListener:VoerkaI18n.off.bind(VoerkaI18n) }
|
||||
{{else}}
|
||||
module.exports.languages = languages
|
||||
module.exports.scope = scope
|
||||
module.exports.t = t
|
||||
module.exports.changeLanguage = VoerkaI18n.change.bind(VoerkaI18n)
|
||||
module.exports.addLanguageListener = VoerkaI18n.on.bind(VoerkaI18n)
|
||||
module.exports.removeLanguageListener = VoerkaI18n.off.bind(VoerkaI18n)
|
||||
module.exports.i18nManager = VoerkaI18n
|
||||
{{/if}}
|
||||
|
@ -1,4 +1,6 @@
|
||||
|
||||
const path = require("path")
|
||||
const fs = require("fs")
|
||||
const readJson = require("readjson")
|
||||
|
||||
async function importModule(url){
|
||||
try{
|
||||
@ -21,10 +23,25 @@ async function importModule(url){
|
||||
let parent = path.dirname(folder)
|
||||
if(parent===folder) return null
|
||||
return findModuleType(parent)
|
||||
}catch{
|
||||
}catch(e){
|
||||
return "esm"
|
||||
}
|
||||
}
|
||||
|
||||
function createPackageJsonFile(targetPath,moduleType="auto"){
|
||||
if(moduleType==="auto"){
|
||||
moduleType = findModuleType(targetPath)
|
||||
}
|
||||
const packageJsonFile = path.join(targetPath, "package.json")
|
||||
if(["esm","es"].includes(moduleType)){
|
||||
fs.writeFileSync(packageJsonFile,JSON.stringify({type:"module",license:"MIT"},null,4))
|
||||
}else{
|
||||
fs.writeFileSync(packageJsonFile,JSON.stringify({license:"MIT"},null,4))
|
||||
}
|
||||
return moduleType
|
||||
}
|
||||
|
||||
|
||||
function isPlainObject(obj){
|
||||
if (typeof obj !== 'object' || obj === null) return false;
|
||||
var proto = Object.getPrototypeOf(obj);
|
||||
@ -95,7 +112,8 @@ function createJsModuleFile(filename,defaultExports={},namedExports={},moduleTyp
|
||||
}
|
||||
module.exports = {
|
||||
importModule,
|
||||
findModuleType
|
||||
findModuleType,
|
||||
createPackageJsonFile
|
||||
}
|
||||
|
||||
|
||||
|
15
pnpm-lock.yaml
generated
15
pnpm-lock.yaml
generated
@ -92,9 +92,10 @@ importers:
|
||||
art-template: ^4.13.2
|
||||
commander: ^9.0.0
|
||||
deepmerge: ^4.2.2
|
||||
dotenv: ^16.0.0
|
||||
glob: ^7.2.0
|
||||
gulp: ^4.0.2
|
||||
logsets: ^1.0.7
|
||||
logsets: ^1.0.8
|
||||
readjson: ^2.2.2
|
||||
through2: ^4.0.2
|
||||
vinyl: ^2.2.1
|
||||
@ -105,9 +106,10 @@ importers:
|
||||
art-template: 4.13.2
|
||||
commander: 9.0.0
|
||||
deepmerge: 4.2.2
|
||||
dotenv: 16.0.0
|
||||
glob: 7.2.0
|
||||
gulp: 4.0.2
|
||||
logsets: 1.0.7
|
||||
logsets: 1.0.8
|
||||
readjson: 2.2.2
|
||||
through2: 4.0.2
|
||||
vinyl: 2.2.1
|
||||
@ -2567,6 +2569,11 @@ packages:
|
||||
webidl-conversions: 5.0.0
|
||||
dev: true
|
||||
|
||||
/dotenv/16.0.0:
|
||||
resolution: {integrity: sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==}
|
||||
engines: {node: '>=12'}
|
||||
dev: false
|
||||
|
||||
/duplexify/3.7.1:
|
||||
resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==}
|
||||
dependencies:
|
||||
@ -4166,8 +4173,8 @@ packages:
|
||||
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
|
||||
dev: true
|
||||
|
||||
/logsets/1.0.7:
|
||||
resolution: {integrity: sha512-O9VFAcMEuUY1tyq81hdZada+77fLl2Ff602AhlKpEpVr3gMyPFM67tILlBZZgnCfcmoRUo6nwhl26xXURHPH0A==}
|
||||
/logsets/1.0.8:
|
||||
resolution: {integrity: sha512-9XuCtIjGvAWbi+JgF2+NI5Bb55uvzwgCFvlo/pafXdZjVC0DDri2k+Jzv7hWg0audTrw4FTnIBiSo3yOlEpmHQ==}
|
||||
dependencies:
|
||||
'@babel/runtime-corejs3': registry.npmmirror.com/@babel/runtime-corejs3/7.17.2
|
||||
ansicolor: registry.npmmirror.com/ansicolor/1.1.100
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* 测试demp app的语言运行环境
|
||||
*/
|
||||
const compile = require('../packages/tools/compile');
|
||||
const compile = require('../packages/tools/compile.command');
|
||||
const path = require("path")
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user