├── .npmrc ├── .npmignore ├── test ├── translate-file │ ├── translate.md │ ├── source.md │ ├── source.zh.md │ ├── translate-values.md │ └── values.test.js ├── feature │ ├── testWrite3.zh.md │ ├── testWrite1.md │ ├── testWrite1.zh.md │ ├── testWrite3.en.md │ ├── testWrite3.md │ ├── testWrite.md │ └── testWrite.zh.md ├── readmd.test.js ├── mergeConfig.js ├── Fix │ ├── testWithSymbal.zh.md │ ├── testWithSymbal.md │ ├── fixFileTooBig.test.js │ └── lengthEqual.test.js ├── disk-cache │ └── disk.js ├── writeDataToFile.test.js ├── cli.test.js ├── logger │ ├── debugMgs.test.js │ └── logger.test.js ├── translateExports.test.js ├── setObjectKey.test.js ├── optionsTodo.test.js ├── setObjectKey.Object.js └── cutMdhead.test.js ├── src ├── util │ ├── readmd.js │ ├── cutMdhead.js │ ├── diskCache.js │ ├── writeDataToFile.js │ ├── debugMsg.js │ └── util.js ├── Fix │ ├── fixZhtoEn.js │ ├── fixFileTooBig.js │ └── lengthEqual.js ├── config │ ├── work-options.js │ ├── defaultConfig.json │ ├── loggerConfig.js │ ├── optionsTodo.js │ └── mergeConfig.js ├── typeSetAndGet.js ├── translateMds.js └── setObjectKey.js ├── imgs └── demo.gif ├── .editorconfig ├── md ├── 2.zh.md ├── about │ ├── 3.zh.md │ ├── 3.md │ └── aboutme │ │ ├── me.zh.md │ │ └── me.md ├── start │ ├── index.zh.md │ └── index.md ├── 2.md ├── 1.zh.md └── 1.md ├── .travis.yml ├── .gitignore ├── .vscode └── launch.json ├── package.json ├── NodePathdata.json ├── README.md ├── README.en.md ├── cli.js ├── License └── CHANGELOG.md /.npmrc: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test 2 | md 3 | imgs 4 | -------------------------------------------------------------------------------- /test/translate-file/translate.md: -------------------------------------------------------------------------------- 1 | 你好 世界 2 | -------------------------------------------------------------------------------- /test/feature/testWrite3.zh.md: -------------------------------------------------------------------------------- 1 | hello! 2 | world -------------------------------------------------------------------------------- /test/translate-file/source.md: -------------------------------------------------------------------------------- 1 | hello world 2 | -------------------------------------------------------------------------------- /test/translate-file/source.zh.md: -------------------------------------------------------------------------------- 1 | 你好 世界 2 | 3 | -------------------------------------------------------------------------------- /test/translate-file/translate-values.md: -------------------------------------------------------------------------------- 1 | hello world -------------------------------------------------------------------------------- /src/util/readmd.js: -------------------------------------------------------------------------------- 1 | module.exports = require('files-list') 2 | -------------------------------------------------------------------------------- /src/Fix/fixZhtoEn.js: -------------------------------------------------------------------------------- 1 | module.exports = require('zh-to-en-symbol') 2 | -------------------------------------------------------------------------------- /imgs/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chinanf-boy/translate-mds/HEAD/imgs/demo.gif -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.yml] 11 | indent_style = space 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /src/config/work-options.js: -------------------------------------------------------------------------------- 1 | const Dconfig = require('./defaultConfig.json') 2 | 3 | let Options = Dconfig 4 | 5 | function setOptions(options){ 6 | Options = options 7 | } 8 | 9 | function getOptions(){ 10 | return Options 11 | } 12 | 13 | module.exports = { 14 | setOptions, 15 | getOptions 16 | } 17 | -------------------------------------------------------------------------------- /src/util/cutMdhead.js: -------------------------------------------------------------------------------- 1 | module.exports = cutMdhead = (data) =>{ 2 | let headlike = ['---','+++'] 3 | for(let i in headlike) 4 | if(data.startsWith( headlike[i] )){ 5 | let index = data.slice(3).indexOf( headlike[i] ) + 6 6 | return [data.slice(index), data.slice(0,index)+'\n\n'] 7 | 8 | } 9 | return [data, ""] 10 | } 11 | -------------------------------------------------------------------------------- /test/readmd.test.js: -------------------------------------------------------------------------------- 1 | const { test } = require('ava') 2 | 3 | const Listmd = require('../src/util/readmd.js') 4 | 5 | test("read zh md folder", async t =>{ 6 | const len = await Listmd(__dirname+"/../md/",{ deep: 'all' }) 7 | t.is(len.length, 10) 8 | }) 9 | 10 | test("read md file", async t =>{ 11 | const len = await Listmd(__dirname+"/feature/testWrite.md") 12 | t.is(len.length, 1) 13 | }) 14 | -------------------------------------------------------------------------------- /test/mergeConfig.js: -------------------------------------------------------------------------------- 1 | import test from 'ava' 2 | import mergeConfig from '../src/config/mergeConfig' 3 | 4 | test('cli config',t =>{ 5 | let cli = { 6 | flags:{ 7 | F:true, 8 | G:true, 9 | values:true, 10 | translate: 'hello', 11 | timewait: '1000' 12 | } 13 | } 14 | 15 | let config = mergeConfig(cli) 16 | 17 | t.is(Object.keys(config).length,10) 18 | }) 19 | -------------------------------------------------------------------------------- /src/config/defaultConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "logger": { 3 | "level": "info" 4 | }, 5 | "api": "google", 6 | "from": false, 7 | "to": "zh", 8 | "num": 1, 9 | "rewrite": false, 10 | "com": false, 11 | "force": false, 12 | "timewait": "80", 13 | "getvalues": false, 14 | "translate": false, 15 | "apis": ["baidu", "google", "youdao"], 16 | "ignore": false, 17 | "matchs": [], 18 | "types": [], 19 | "skips": [], 20 | "textGlob": false, 21 | "disk": true, 22 | "zh":true, 23 | "cache": false, 24 | "cacheName": "translateMds" 25 | } 26 | -------------------------------------------------------------------------------- /test/Fix/testWithSymbal.zh.md: -------------------------------------------------------------------------------- 1 | # 真棒冷阵雨 2 | 3 | 当人们对事物感到兴奋时,这很好,但有时他们会有一点点兴奋_太_兴奋. 这是一个真棒(严谨和尊重),并策划(我阅读每一个建议,并作出判断呼吁)冷水淋浴名单上overhyped topics.this做**不**意味着热情是不好的或错误的: 我们只是提醒人们保持接地. 随时提交你的最爱! 4 | 5 | #### [验证技术](http://www.cypherpunks.to/~peter/04_verif_techniques.pdf)(PDF) 6 | 7 | - **炒作: **"正式验证是写软件的好方法,我们应该证明我们所有的代码都是正确的. "淋浴: 8 | 9 | - **大量的文献回顾显示,正式的方法很难学,应用的代价极其昂贵,并且经常错过重要的错误. **注意事项: 10 | 11 | - **写于2000年,并不包括现代工具/技术,如Tla +或从属打字. **笔记: 12 | 13 | - **部分**彼得古特曼[的论文,"密码安全体系结构的设计和验证". ](https://www.cs.auckland.ac.nz/~pgut001/)的论文,"密码安全体系结构的设计和验证". -------------------------------------------------------------------------------- /md/2.zh.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Hugo Documentation 3 | linktitle: Hugo 4 | description: Hugo is the world's fastest static website engine. It's written in Go (aka Golang) and developed by bep, spf13 and friends. 5 | date: 2017-02-01 6 | publishdate: 2017-02-01 7 | lastmod: 2017-02-01 8 | menu: 9 | main: 10 | parent: "section name" 11 | weight: 01 12 | weight: 01 #rem 13 | draft: false 14 | slug: 15 | aliases: [] 16 | toc: false 17 | layout: documentation-home 18 | --- 19 | 雨果是**世界上最快的静态网站引擎. **它是用去(aka Golang)开发的[BEP](https://github.com/bep),[spf13](https://github.com/spf13)和[朋友](https://github.com/gohugoio/hugo/graphs/contributors). 下面您将从我们的文档中找到一些最常见和最有用的页面. 20 | 21 | 你好 22 | -------------------------------------------------------------------------------- /md/about/3.zh.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Hugo Documentation 3 | linktitle: Hugo 4 | description: Hugo is the world's fastest static website engine. It's written in Go (aka Golang) and developed by bep, spf13 and friends. 5 | date: 2017-02-01 6 | publishdate: 2017-02-01 7 | lastmod: 2017-02-01 8 | menu: 9 | main: 10 | parent: "section name" 11 | weight: 01 12 | weight: 01 #rem 13 | draft: false 14 | slug: 15 | aliases: [] 16 | toc: false 17 | layout: documentation-home 18 | --- 19 | 雨果是**世界上最快的静态网站引擎. **它是用去(aka Golang)开发的[BEP](https://github.com/bep),[spf13](https://github.com/spf13)和[朋友](https://github.com/gohugoio/hugo/graphs/contributors). 下面您将从我们的文档中找到一些最常见和最有用的页面. 20 | 21 | 你好 22 | -------------------------------------------------------------------------------- /md/start/index.zh.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Hugo Documentation 3 | linktitle: Hugo 4 | description: Hugo is the world's fastest static website engine. It's written in Go (aka Golang) and developed by bep, spf13 and friends. 5 | date: 2017-02-01 6 | publishdate: 2017-02-01 7 | lastmod: 2017-02-01 8 | menu: 9 | main: 10 | parent: "section name" 11 | weight: 01 12 | weight: 01 #rem 13 | draft: false 14 | slug: 15 | aliases: [] 16 | toc: false 17 | layout: documentation-home 18 | --- 19 | 雨果是**世界上最快的静态网站引擎. **它是用去(aka Golang)开发的[BEP](https://github.com/bep),[spf13](https://github.com/spf13)和[朋友](https://github.com/gohugoio/hugo/graphs/contributors). 下面您将从我们的文档中找到一些最常见和最有用的页面. 20 | 21 | 你好 22 | -------------------------------------------------------------------------------- /test/translate-file/values.test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | process.chdir(__dirname + '/../../'); 3 | 4 | const path = require('path'); 5 | const execa = require('execa'); 6 | 7 | test('use --values [path]', async t => { 8 | let err = await t.throws( 9 | execa.shell( 10 | 'node cli.js ./test/translate-file/source.md --values ./test/translate-file/translate-values.md -R' 11 | ) 12 | ); 13 | t.regex(err.message, /values save/); 14 | }); 15 | 16 | test('use --translate [path]', async t => { 17 | let err = await execa.shell( 18 | 'node cli.js ./test/translate-file/source.md --translate ./test/translate-file/translate.md -R' 19 | ); 20 | t.regex(err.stderr, /be The translation/); 21 | }); 22 | -------------------------------------------------------------------------------- /test/disk-cache/disk.js: -------------------------------------------------------------------------------- 1 | const {test} = require('ava'); 2 | const dbFunc = require('../../src/util/diskCache'); 3 | 4 | const DBname = 'test-disk'; 5 | let dbFace = dbFunc(DBname); 6 | const OBJ = {author: 'name'}; 7 | 8 | test.serial('get obj', async t => { 9 | let res = await dbFace.getDisk(DBname, {nothing:1}); 10 | t.deepEqual(res, undefined); 11 | }); 12 | test.serial('set obj', async t => { 13 | let res = await dbFace.setDisk(DBname, OBJ, OBJ); 14 | console.log(res); 15 | t.true(Object.keys(res).some(x => res[x] > 0)); 16 | }); 17 | 18 | test.serial('get obj', async t => { 19 | let res = await dbFace.getDisk(DBname); 20 | t.deepEqual(res.author, OBJ.author); 21 | }); 22 | test.serial('db path', t => { 23 | t.true(dbFace.path.includes('disks')); 24 | }); 25 | -------------------------------------------------------------------------------- /md/2.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Hugo Documentation 3 | linktitle: Hugo 4 | description: Hugo is the world's fastest static website engine. It's written in Go (aka Golang) and developed by bep, spf13 and friends. 5 | date: 2017-02-01 6 | publishdate: 2017-02-01 7 | lastmod: 2017-02-01 8 | menu: 9 | main: 10 | parent: "section name" 11 | weight: 01 12 | weight: 01 #rem 13 | draft: false 14 | slug: 15 | aliases: [] 16 | toc: false 17 | layout: documentation-home 18 | --- 19 | Hugo is the **world's fastest static website engine.** It's written in Go (aka Golang) and developed by [bep](https://github.com/bep), [spf13](https://github.com/spf13) and [friends](https://github.com/gohugoio/hugo/graphs/contributors). Below you will find some of the most common and helpful pages from our documentation. 20 | 21 | 你好 -------------------------------------------------------------------------------- /md/about/3.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Hugo Documentation 3 | linktitle: Hugo 4 | description: Hugo is the world's fastest static website engine. It's written in Go (aka Golang) and developed by bep, spf13 and friends. 5 | date: 2017-02-01 6 | publishdate: 2017-02-01 7 | lastmod: 2017-02-01 8 | menu: 9 | main: 10 | parent: "section name" 11 | weight: 01 12 | weight: 01 #rem 13 | draft: false 14 | slug: 15 | aliases: [] 16 | toc: false 17 | layout: documentation-home 18 | --- 19 | Hugo is the **world's fastest static website engine.** It's written in Go (aka Golang) and developed by [bep](https://github.com/bep), [spf13](https://github.com/spf13) and [friends](https://github.com/gohugoio/hugo/graphs/contributors). Below you will find some of the most common and helpful pages from our documentation. 20 | 21 | 你好 -------------------------------------------------------------------------------- /test/feature/testWrite1.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Hugo Documentation 3 | linktitle: Hugo 4 | description: Hugo is the world's fastest static website engine. It's written in Go (aka Golang) and developed by bep, spf13 and friends. 5 | date: 2017-02-01 6 | publishdate: 2017-02-01 7 | lastmod: 2017-02-01 8 | menu: 9 | main: 10 | parent: "section name" 11 | weight: 01 12 | weight: 01 #rem 13 | draft: false 14 | slug: 15 | aliases: [] 16 | toc: false 17 | layout: documentation-home 18 | --- 19 | Hugo is the **world's fastest static website engine.** It's written in Go (aka Golang) and developed by [bep](https://github.com/bep), [spf13](https://github.com/spf13) and [friends](https://github.com/gohugoio/hugo/graphs/contributors). Below you will find some of the most common and helpful pages from our documentation. -------------------------------------------------------------------------------- /test/feature/testWrite1.zh.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Hugo Documentation 3 | linktitle: Hugo 4 | description: Hugo is the world's fastest static website engine. It's written in Go (aka Golang) and developed by bep, spf13 and friends. 5 | date: 2017-02-01 6 | publishdate: 2017-02-01 7 | lastmod: 2017-02-01 8 | menu: 9 | main: 10 | parent: "section name" 11 | weight: 01 12 | weight: 01 #rem 13 | draft: false 14 | slug: 15 | aliases: [] 16 | toc: false 17 | layout: documentation-home 18 | --- 19 | Hugo is the **world's fastest static website engine.** It's written in Go (aka Golang) and developed by [bep](https://github.com/bep), [spf13](https://github.com/spf13) and [friends](https://github.com/gohugoio/hugo/graphs/contributors). Below you will find some of the most common and helpful pages from our documentation. -------------------------------------------------------------------------------- /test/feature/testWrite3.en.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Hugo Documentation 3 | linktitle: Hugo 4 | description: Hugo is the world's fastest static website engine. It's written in Go (aka Golang) and developed by bep, spf13 and friends. 5 | date: 2017-02-01 6 | publishdate: 2017-02-01 7 | lastmod: 2017-02-01 8 | menu: 9 | main: 10 | parent: "section name" 11 | weight: 01 12 | weight: 01 #rem 13 | draft: false 14 | slug: 15 | aliases: [] 16 | toc: false 17 | layout: documentation-home 18 | --- 19 | Hugo is the **world's fastest static website engine.** It's written in Go (aka Golang) and developed by [bep](https://github.com/bep), [spf13](https://github.com/spf13) and [friends](https://github.com/gohugoio/hugo/graphs/contributors). Below you will find some of the most common and helpful pages from our documentation. -------------------------------------------------------------------------------- /test/feature/testWrite3.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Hugo Documentation 3 | linktitle: Hugo 4 | description: Hugo is the world's fastest static website engine. It's written in Go (aka Golang) and developed by bep, spf13 and friends. 5 | date: 2017-02-01 6 | publishdate: 2017-02-01 7 | lastmod: 2017-02-01 8 | menu: 9 | main: 10 | parent: "section name" 11 | weight: 01 12 | weight: 01 #rem 13 | draft: false 14 | slug: 15 | aliases: [] 16 | toc: false 17 | layout: documentation-home 18 | --- 19 | Hugo is the **world's fastest static website engine.** It's written in Go (aka Golang) and developed by [bep](https://github.com/bep), [spf13](https://github.com/spf13) and [friends](https://github.com/gohugoio/hugo/graphs/contributors). Below you will find some of the most common and helpful pages from our documentation. -------------------------------------------------------------------------------- /md/start/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Hugo Documentation 3 | linktitle: Hugo 4 | description: Hugo is the world's fastest static website engine. It's written in Go (aka Golang) and developed by bep, spf13 and friends. 5 | date: 2017-02-01 6 | publishdate: 2017-02-01 7 | lastmod: 2017-02-01 8 | menu: 9 | main: 10 | parent: "section name" 11 | weight: 01 12 | weight: 01 #rem 13 | draft: false 14 | slug: 15 | aliases: [] 16 | toc: false 17 | layout: documentation-home 18 | --- 19 | Hugo is the **world's fastest static website engine.** It's written in Go (aka Golang) and developed by [bep](https://github.com/bep), [spf13](https://github.com/spf13) and [friends](https://github.com/gohugoio/hugo/graphs/contributors). Below you will find some of the most common and helpful pages from our documentation. 20 | 21 | 你好 -------------------------------------------------------------------------------- /test/feature/testWrite.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Hugo Documentation 3 | linktitle: Hugo 4 | description: Hugo is the world's fastest static website engine. It's written in Go (aka Golang) and developed by bep, spf13 and friends. 5 | date: 2017-02-01 6 | publishdate: 2017-02-01 7 | lastmod: 2017-02-01 8 | menu: 9 | main: 10 | parent: "section name" 11 | weight: 01 12 | weight: 01 #rem 13 | draft: false 14 | slug: 15 | aliases: [] 16 | toc: false 17 | layout: documentation-home 18 | --- 19 | Hugo is the **world's fastest static website engine.** It's written in Go (aka Golang) and developed by [bep](https://github.com/bep), [spf13](https://github.com/spf13) and [friends](https://github.com/gohugoio/hugo/graphs/contributors). Below you will find some of the most common and helpful pages from our documentation. 20 | ➜ /Users/lizhenyong/Desk -------------------------------------------------------------------------------- /test/feature/testWrite.zh.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Hugo Documentation 3 | linktitle: Hugo 4 | description: Hugo is the world's fastest static website engine. It's written in Go (aka Golang) and developed by bep, spf13 and friends. 5 | date: 2017-02-01 6 | publishdate: 2017-02-01 7 | lastmod: 2017-02-01 8 | menu: 9 | main: 10 | parent: "section name" 11 | weight: 01 12 | weight: 01 #rem 13 | draft: false 14 | slug: 15 | aliases: [] 16 | toc: false 17 | layout: documentation-home 18 | --- 19 | Hugo is the **world's fastest static website engine.** It's written in Go (aka Golang) and developed by [bep](https://github.com/bep), [spf13](https://github.com/spf13) and [friends](https://github.com/gohugoio/hugo/graphs/contributors). Below you will find some of the most common and helpful pages from our documentation. 20 | ➜ /Users/lizhenyong/Desk -------------------------------------------------------------------------------- /src/util/diskCache.js: -------------------------------------------------------------------------------- 1 | var dbS = require("diskdb"); 2 | const path = require("path"); 3 | const fs = require("fs"); 4 | 5 | const localPath = () => path.join(__dirname, "../../disks"); 6 | 7 | function loadDisk(...filename) { 8 | // fixed: missing path 9 | let lP = localPath(); 10 | if (!fs.existsSync(lP)) { 11 | fs.mkdirSync(lP); 12 | } 13 | let db = dbS.connect(lP, [...filename]); 14 | 15 | let options = { 16 | multi: false, // update multiple - default false 17 | upsert: true, // if object is not found, add it (update-insert) - default false 18 | }; 19 | 20 | function setDisk(key, q, obj) { 21 | return db[key].update(q, obj, options); 22 | } 23 | 24 | function getDisk(key, obj) { 25 | return db[key].findOne(obj); 26 | } 27 | 28 | return { setDisk, getDisk, db, path: db._db.path }; 29 | } 30 | 31 | module.exports = loadDisk; 32 | -------------------------------------------------------------------------------- /test/writeDataToFile.test.js: -------------------------------------------------------------------------------- 1 | const { test } = require('ava') 2 | const fs = require('fs') 3 | 4 | const { writeDataToFile } = require('../src/util/writeDataToFile.js') 5 | const { insert_flg } = require('../src/util/util.js') 6 | 7 | test("get new filename ",t =>{ 8 | let result = insert_flg('aaaa.md', '.zh', 3) 9 | t.is(result, 'aaaa.zh.md') 10 | }) 11 | 12 | test.failing("get bad filename ",t =>{ 13 | insert_flg('', '.zh', 3) 14 | t.fail('这里是传入不正确的文件名') 15 | }) 16 | 17 | test.failing("filename no .md", async t =>{ 18 | await writeDataToFile('data', __dirname + '') 19 | 20 | }) 21 | 22 | test.serial("writeData with Array ", async t =>{ 23 | let result = await writeDataToFile(["hello!", "world"], __dirname + '/feature/testWrite3.md') 24 | t.true(result.includes('file saved')) 25 | }) 26 | 27 | test.failing("filename Array ", async t =>{ 28 | await writeDataToFile(['data','data'], __dirname + '') 29 | }) 30 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 8 4 | - 9 5 | - 10 6 | script: 7 | - npm test 8 | after_success: 9 | - bash <(curl -s https://codecov.io/bash) 10 | deploy: 11 | provider: npm 12 | email: yobrave@outlook.com 13 | api_key: 14 | secure: ZBbhBBFZ0mOvIhuXZwmK87h7JnwPAkEP88qaBx7jELHdos0r7O7G0F6Tb+Zfw7UWM2aJPXrMthH28rsbpr3zGX0Y3qD5VmfyeGWSZd+UimEmEYpQpJ1rilpynkMLpbBeultapN1bN4ZWGwDYsyoXNC4Y/lfleq+ZKE0O80oBqu8M1EXN1QJrCnV7lIz7R+FRk/EP3jo0LZ0ZBAWuhSbJ4JWzliD41NCJVanoT1qj//3+NXEgKCOPc2lvG31AhYDCj0C0/34MY1woS8laVEY5qA3fGUljktob2edcv1+VThZ8rP7yYKiKVmdd6mJpkDEBxAm8zR1FKg19Il1wo/20F2e/41wcaHch8WNXJWHXSaduXzK2VE5obsRTkwWL5WRddmdSsRuL3yu8W79wrMEh48oJXWHEP05dDAPxr7tmjEJke68fIOjdeAERU3V7hgSohjEgHLDRG1O7OskFX+FuUC5tDh+fYjVF0LgduR8OyLspXZgBwy2+Z0GyGaIhgVMGPsxZJkenXC0G8YMqzbqdakfBtEQrW8zXMSfa+FcsdbxnU6DW/BWNUFVCRfiabE453YuWh2/KzVSGKXmtIqqNkZpicDeZwsA691Ci6QwOIEx1ISo+aN8gCYO/U4PoSLDYfKxZvoBLNtvi/RNQxfAN9j0kIL3MRmKU3Fok0MsRNDI= 15 | on: 16 | branch: master 17 | tags: true 18 | repo: chinanf-boy/translate-mds 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *DS 2 | node_modules/ 3 | .nyc_ou* 4 | *.log 5 | npm-debug.log* 6 | 7 | # vscode debug 8 | try.js 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | 15 | # Directory for instrumented libs generated by jscoverage/JSCover 16 | lib-cov 17 | 18 | # Coverage directory used by tools like istanbul 19 | coverage 20 | 21 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 22 | .grunt 23 | 24 | # node-waf configuration 25 | .lock-wscript 26 | 27 | # Compiled binary addons (http://nodejs.org/api/addons.html) 28 | build/* 29 | 30 | # Dependency directory 31 | # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git 32 | node_modules 33 | 34 | # Static file 35 | public 36 | 37 | # Bower 38 | bower_components 39 | 40 | # Optional npm cache directory 41 | .npm 42 | 43 | # Optional REPL history 44 | .node_repl_history 45 | 46 | .idea/* 47 | /coverage 48 | .DS_Store 49 | src/config/config.local* 50 | src/config/sequelize.json 51 | lib/* 52 | .nyc_output 53 | ./config.json 54 | disks 55 | -------------------------------------------------------------------------------- /src/util/writeDataToFile.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const { m,insert_flg,relaPath,g } = require('./util') 3 | const { 4 | logger 5 | } = require('../config/loggerConfig.js'); 6 | const { 7 | getOptions 8 | } = require('../config/work-options.js'); 9 | let configs = getOptions() 10 | const tranT = configs.to 11 | 12 | 13 | const writeDataToFile = async (data, file_dir) => { 14 | return new Promise((ok, Err) => { 15 | try{ 16 | 17 | let zhfile 18 | if (!file_dir.endsWith('.md')) { 19 | Err("no md file,just go away") 20 | } 21 | require.resolve(file_dir) 22 | 23 | zhfile = insert_flg(file_dir, `.${tranT}`, 3) 24 | 25 | // data is Array 26 | if (data instanceof Array) { 27 | data = data.join("\n") 28 | } 29 | 30 | 31 | fs.writeFile(zhfile + '', data, (err) => { 32 | if (err) 33 | Err(err); 34 | ok(`4. ${m(tranT)} file saved! -->> ${g(relaPath(zhfile))}`) 35 | }); 36 | 37 | }catch(err){ 38 | Err(err) 39 | } 40 | }) 41 | } 42 | 43 | 44 | module.exports = { 45 | writeDataToFile, 46 | insert_flg 47 | } 48 | -------------------------------------------------------------------------------- /test/Fix/testWithSymbal.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Awesome Cold Showers 4 | 5 | It's great when people get excited about things, but sometimes they get a little _too_ excited. This an awesome (rigorous and respectful) and curated (I read every suggestion and make judgement calls) list of cold showers on overhyped topics.This does **not** mean the enthusiasm is bad or wrong: we're just reminding people to stay grounded. Feel free to submit your favorites! 6 | 7 | #### [Verification Techniques](http://www.cypherpunks.to/~peter/04_verif_techniques.pdf) (PDF) 8 | 9 | * **Hype:** "Formal Verification is a great way to write software. We should prove all of our code correct." 10 | 11 | * **Shower:** Extensive literature review showing that formal methods are hard to learn, extremely expensive to apply, and often miss critical bugs. 12 | 13 | * **Caveats:** Written in 2000 and doesn't cover modern tools/techniques, such as TLA+ or dependent typing. 14 | 15 | * **Notes:** Part of [Peter Gutmann](https://www.cs.auckland.ac.nz/~pgut001/)'s thesis, "The Design and Verification of a Cryptographic Security Architecture". 16 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // 使用 IntelliSense 了解相关属性。 3 | // 悬停以查看现有属性的描述。 4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Launch try export", 11 | "program": "${workspaceFolder}/try.js" 12 | }, 13 | { 14 | "type": "node", 15 | "request": "launch", 16 | "name": "Launch src/write", 17 | "program": "${workspaceFolder}/src/writeDataToFile.js" 18 | }, 19 | { 20 | "type": "node", 21 | "request": "launch", 22 | "name": "Launch src/readmd", 23 | "program": "${workspaceFolder}/src/readmd.js" 24 | }, 25 | { 26 | "type": "node", 27 | "request": "launch", 28 | "name": "Launch index", 29 | "program": "${workspaceFolder}/cli.js", 30 | "args": [ 31 | "test/feature/testWrite.md" 32 | ] 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /test/cli.test.js: -------------------------------------------------------------------------------- 1 | const { test } = require('ava') 2 | const path = require('path') 3 | const execa = require('execa') 4 | process.chdir(path.resolve(__dirname+'/..')); 5 | 6 | let a = `./test/feature/testWrite3.en.md` 7 | let b = `./test/translate-file/translate-values.md` 8 | 9 | 10 | test('show help screen', async t => { 11 | t.regex(await execa.shell('node cli.js').then(x=>x.stderr).catch(x =>x.stderr), /translate/) 12 | }); 13 | 14 | test('--glob', async t => { 15 | t.regex(await execa.shell(`node cli.js ${b} --glob *.js -D`).then(x=>x.stderr), /glob/) 16 | }); 17 | 18 | test('--ignore', async t => { 19 | t.regex(await execa.shell(`node cli.js ${b} --ignore ${b} -D`).then(x=>x.stderr), /ignore/) 20 | }); 21 | 22 | test('已翻译', async t => { 23 | t.regex(await execa.shell(`node cli.js ./md -D`).then(x=>x.stderr), /已翻译/) 24 | }); 25 | 26 | test('国家后缀', async t => { 27 | t.regex(await execa.shell(`node cli.js ${a} -D`).then(x=>x.stderr), /国家/) 28 | }); 29 | 30 | test('show version', async t => { 31 | t.is(await execa.shell('node cli.js --version').then(x=>x.stdout), require('../package').version); 32 | }); 33 | -------------------------------------------------------------------------------- /test/logger/debugMgs.test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | const debugMsg = require('../../src/util/debugMsg'); 3 | const debug = require('debug')('mds:tran'); 4 | const { 5 | logger, 6 | loggerStart, 7 | loggerText, 8 | oneOra, 9 | _SETDEBUG 10 | } = require('../../src/config/loggerConfig.js'); 11 | 12 | const source1 = ['Hello', 'World']; 13 | const result1 = ['你好', '世界', '. ']; 14 | const matstr = '2. set-'; 15 | 16 | test('debug msg step 1', t => { 17 | loggerStart('debug 1 running ...'); 18 | 19 | debugMsg(1, source1, result1); 20 | t.pass('debug 1'); 21 | }); 22 | 23 | test('debug msg step 2', t => { 24 | loggerStart('debug 2 running ...'); 25 | 26 | debugMsg(2, source1, result1); 27 | t.pass('debug 2'); 28 | }); 29 | 30 | test('debug msg step 1:debug', t => { 31 | process.env.DEBUG = '*'; 32 | 33 | _SETDEBUG(true); 34 | 35 | loggerStart('debug 1 running ...'); 36 | 37 | debugMsg(1, source1, result1); 38 | t.pass('debug 1'); 39 | }); 40 | 41 | test('debug msg step 2:debug', t => { 42 | process.env.DEBUG = '*'; 43 | 44 | _SETDEBUG(true); 45 | loggerStart('debug 2 running ...'); 46 | 47 | debugMsg(2, source1, result1); 48 | t.pass('debug 2'); 49 | }); 50 | -------------------------------------------------------------------------------- /test/logger/logger.test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | const { logger, 3 | loggerStart, 4 | loggerText, 5 | loggerStop, 6 | getLogger, 7 | _SETDEBUG } = require('../../src/config/loggerConfig') 8 | 9 | const H = "hello world" 10 | 11 | test.todo("logger") 12 | 13 | test.serial('start', t => { 14 | loggerStart(H) 15 | let L = getLogger() 16 | t.true(L !== undefined) 17 | }); 18 | 19 | test.serial('text', t => { 20 | loggerText(H) 21 | t.is(getLogger().text, H) 22 | }); 23 | 24 | test.serial(' stop', t => { 25 | loggerStop() 26 | t.true(!getLogger()) 27 | }); 28 | 29 | test.serial(' stop with succeed', t => { 30 | loggerStart(H) 31 | loggerStop('ok',{ora:'succeed'}) 32 | t.true(!getLogger()) 33 | }); 34 | 35 | test.serial('stop with no start ', t => { 36 | 37 | t.true(!loggerStop("ok done")) 38 | }); 39 | 40 | test.todo("logger DEBUG") 41 | 42 | test('start DEBUG', t => { 43 | _SETDEBUG(true) 44 | loggerStart(H) 45 | let L = getLogger() 46 | t.true(L !== undefined) 47 | }); 48 | 49 | test('text DEBUG', t => { 50 | loggerText(H) 51 | t.is(!!getLogger().debug, true) 52 | }); 53 | 54 | test(' stop DEBUG', t => { 55 | loggerStop(H) 56 | t.true(!getLogger()) 57 | }); 58 | 59 | test('stop with no start DEBUG', t => { 60 | 61 | t.true(!loggerStop("ok done")) 62 | }); 63 | -------------------------------------------------------------------------------- /test/Fix/fixFileTooBig.test.js: -------------------------------------------------------------------------------- 1 | const { test } = require('ava') 2 | const fs = require('fs') 3 | 4 | const { fixFileTooBig, indexMergeArr, thirdArray } = require('../../src/Fix/fixFileTooBig.js') 5 | 6 | test("fixFileTooBig 1 <= length <= 30 & 1<= string<=300", t =>{ 7 | let a = [] 8 | let n = 30; 9 | let n1 = n 10 | 11 | while(n--){ 12 | a.push(`${n}+hello`) 13 | } 14 | t.is(a.length, n1) 15 | let b = fixFileTooBig(a) 16 | t.is(b.length, 1) 17 | }) 18 | 19 | test("fixFileTooBig length > 30 & 1<= string<=300 ", t =>{ 20 | let a = [] 21 | let n = 31 22 | let n1 = n 23 | while(n--){ 24 | a.push(`${n}+hello`) 25 | } 26 | t.is(a.length, n1) 27 | let b = fixFileTooBig(a) 28 | t.is(b.length, 2) 29 | }) 30 | 31 | test("indexMergeArr Arr ", t =>{ 32 | let a = [1,2,3,4] 33 | let b = indexMergeArr(a, 1, 1) 34 | t.is(b.length, 1) 35 | t.is(b[0], 2) 36 | }) 37 | 38 | test.failing("indexMergeArr B fail", t =>{ 39 | let a = [1,2,3,4] 40 | t.throws(indexMergeArr(a, -1, 7)) 41 | }) 42 | 43 | test("indexMergeArr Arr >[0] + [1]", t =>{ 44 | let a = [1,2,2.5,3,4,] 45 | let b = [] 46 | b[0] = indexMergeArr(a, 0, 3) 47 | b[1] = indexMergeArr(a, 3, (5-3)) 48 | t.deepEqual(b, [[1,2,2.5],[3,4]]) 49 | }) 50 | -------------------------------------------------------------------------------- /src/util/debugMsg.js: -------------------------------------------------------------------------------- 1 | const debug = require('debug')('mds:tran'); 2 | const {tc, g, y, yow, m, b, r} = require('./util.js'); 3 | const { 4 | logger, 5 | loggerStart, 6 | loggerText, 7 | oneOra 8 | } = require('../config/loggerConfig.js'); 9 | 10 | module.exports = debugMsg = (step, valueArr, resArr) => { 11 | let BigOne = valueArr.length > resArr.length ? valueArr : resArr; 12 | let debugInfo = `-- source: ${valueArr.length}/${ 13 | resArr.length 14 | }: translte ---`; 15 | if (resArr.length == 0) return; 16 | 17 | function tranSourceShow(debug) { 18 | for (let i in BigOne) { 19 | // Debug 20 | if (!valueArr[i] || !resArr[i]) { 21 | debug( 22 | `2. set- ${i} : ${g(valueArr[i])} ${tc.bgMagenta( 23 | 'to->' 24 | )} ${i} : ${yow(resArr[i])}` 25 | ); 26 | } else { 27 | debug( 28 | `2. set- ${i} : ${g(valueArr[i])} to-> ${i} : ${yow(resArr[i])}` 29 | ); 30 | } 31 | } 32 | } 33 | 34 | if (step == 1) { 35 | if (debug.enabled) { 36 | // debug all 37 | debug(debugInfo); 38 | 39 | tranSourceShow(debug); 40 | } else { 41 | loggerText(debugInfo); 42 | } 43 | } else { 44 | loggerText(debugInfo); 45 | 46 | tranSourceShow(logger.debug); 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /src/util/util.js: -------------------------------------------------------------------------------- 1 | const tc = require('turbocolor'); 2 | const relative = require('path').relative 3 | let g = tc.green 4 | let y = tc.cyan 5 | let yow = tc.yellow 6 | let m = tc.magenta 7 | let b = tc.blue 8 | let r = tc.red 9 | 10 | 11 | function relaPath(p){ 12 | return relative(process.cwd(),p) 13 | } 14 | 15 | const newObject = (obj) => JSON.parse(JSON.stringify(obj)) 16 | 17 | function time(ms) { 18 | return new Promise((resolve, reject) => { 19 | setTimeout(resolve, ms); 20 | }); 21 | } 22 | 23 | function insert_flg(str, flg, Uindex) { 24 | let newstr = ""; 25 | if (!str || !flg) { 26 | throw TypeError('filename<' + str + '> can not add' + flg) 27 | } 28 | let len = str.length 29 | let tmp = str.substring(0, len - Uindex); 30 | newstr = tmp + flg + str.substring(len - Uindex, len) 31 | return newstr; 32 | } 33 | 34 | function O2A(options) { 35 | let { 36 | aFile, 37 | api, 38 | tF, 39 | tT 40 | } = options 41 | return [aFile, api, tF, tT] 42 | } 43 | 44 | const fs = require('mz/fs') 45 | const EOL = `\n` 46 | 47 | async function asyncWrite(p, arry){ 48 | return await fs.writeFile(p,arry.join(EOL+EOL)) 49 | } 50 | async function asyncRead(p){ 51 | return await fs.readFileSync(p,"utf8").split(EOL+EOL).filter(ok => ok) 52 | } 53 | module.exports = { 54 | time, 55 | g, 56 | y, 57 | yow, 58 | m, 59 | b, 60 | r, 61 | relaPath, 62 | newObject, 63 | insert_flg, 64 | O2A, 65 | asyncWrite, 66 | asyncRead, 67 | tc 68 | } 69 | -------------------------------------------------------------------------------- /src/Fix/fixFileTooBig.js: -------------------------------------------------------------------------------- 1 | const MAXLENGTH = 30; 2 | 3 | /** 4 | * @description fix file-value Too big 5 | * @param {Array} bigArr 6 | */ 7 | function fixFileTooBig(bigArr){ 8 | let chunkArr = [] 9 | let bigL = bigArr.length 10 | let bigl_2 = Math.ceil(bigL/2) 11 | // length > 30 12 | if(bigL > MAXLENGTH){ 13 | 14 | let n = Math.ceil(bigL / MAXLENGTH) // how many chunk 15 | let chunkLength = Math.ceil(bigL/n) // single chunk:Array almost length 16 | 17 | for(let numChunk = 0; numChunk < n ; numChunk ++){ // for chunk length 18 | 19 | // while index+length > bigArr.length , 20 | // we most shrot length in indexMergeArr 21 | chunkArr.push( indexMergeArr(bigArr, (numChunk*chunkLength), chunkLength) ) 22 | } 23 | return chunkArr 24 | }else { // string <= 100 25 | chunkArr.push(bigArr) 26 | return chunkArr 27 | } 28 | } 29 | 30 | /** 31 | * @description 32 | * @param {Array} Arr 33 | * @param {number} B begin 34 | * @param {number} L length 35 | * @returns 36 | */ 37 | function indexMergeArr(Arr, B, L){ 38 | if(B < 0){ 39 | throw new Error("indexMergeArr Arr.length < index -- Error") 40 | } 41 | if(Arr.length < (B+L)){ 42 | //shrot length in indexMergeArr 43 | L = Arr.length - B 44 | } 45 | let backArr = [] 46 | for(let index in Arr){ 47 | if((B <= +index) && (+index < (B+L))){ 48 | backArr.push(Arr[index]) 49 | } 50 | } 51 | return backArr 52 | } 53 | 54 | module.exports = { fixFileTooBig, indexMergeArr } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "translate-mds", 3 | "version": "4.0.5", 4 | "description": "translate [folder/single] md file language to you want", 5 | "main": "./src/translateMds.js", 6 | "engines": { 7 | "node": ">=8.0.0" 8 | }, 9 | "scripts": { 10 | "demo": "node cli.js md/", 11 | "ava": "ava", 12 | "test": "nyc --reporter=lcov --reporter=text --reporter=html npm run ava", 13 | "pub": "npm run test && npm version patch && git push origin master && git push --tags", 14 | "changelog": "github_changelog_generator" 15 | }, 16 | "husky": { 17 | "hooks": {} 18 | }, 19 | "files": [ 20 | "src", 21 | "cli.js" 22 | ], 23 | "ava": { 24 | "files": [ 25 | "test/**/*", 26 | "!test/*.Object.js", 27 | "!config/**", 28 | "!cli.js" 29 | ] 30 | }, 31 | "bin": { 32 | "translateMds": "./cli.js" 33 | }, 34 | "author": "yobrave", 35 | "license": "ISC", 36 | "dependencies": { 37 | "async": "^2.6.0", 38 | "debug": "^3.1.0", 39 | "diskdb": "^0.1.17", 40 | "files-list": "^1.4.1", 41 | "meow": "^3.7.0", 42 | "minimatch": "^3.0.4", 43 | "mz": "^2.7.0", 44 | "ora-min": "^1.0.0", 45 | "remark": "^9.0.0", 46 | "translation.js-fix": "^0.7.8", 47 | "turbocolor": "^2.6.1", 48 | "update-notifier": "^2.5.0", 49 | "what-time": "^0.0.2", 50 | "winston": "^2.4.0", 51 | "zh-to-en-symbol": "^3.0.0" 52 | }, 53 | "keywords": [ 54 | "md", 55 | "translate", 56 | "languages" 57 | ], 58 | "devDependencies": { 59 | "ava": "^0.24.0", 60 | "husky": "1.0.0-rc.13", 61 | "nyc": "^11.3.0" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /test/translateExports.test.js: -------------------------------------------------------------------------------- 1 | const { test } = require('ava') 2 | const path = require('path') 3 | const translate = require('../src/translateMds.js') 4 | 5 | let trueResult = `---\ntitle: Hugo Documentation\nlinktitle: Hugo\ndescription: Hugo is the world\'s fastest static website engine. It\'s written in Go (aka Golang) and developed by bep, spf13 and friends.\ndate: 2017-02-01\npublishdate: 2017-02-01\nlastmod: 2017-02-01\nmenu:\n main:\n parent: \"section name\"\n weight: 01\nweight: 01\t#rem\ndraft: false\nslug:\naliases: []\ntoc: false\nlayout: documentation-home\n---\n雨果是**世界上最快的静态网站引擎。**它是用去(aka Golang)开发的[BEP](https://github.com/bep),[spf13](https://github.com/spf13)和[朋友](https://github.com/gohugoio/hugo/graphs/contributors)。下面您将从我们的文档中找到一些最常见和最有用的页面。\n` 6 | 7 | test.failing('translate no absolute file fail', async t =>{ 8 | let results = await translate(['./feature/testWrite1.md']) 9 | t.fail() 10 | }) 11 | 12 | test.failing('translate nothing', async t =>{ 13 | let results = await translate("") 14 | t.fail() 15 | }) 16 | test.failing('translate input Object fail', async t =>{ 17 | let results = await translate({}) 18 | t.fail() 19 | }) 20 | test.serial('translate absolute file ', async t =>{ 21 | let results = await translate({aFile:__dirname+'/feature/testWrite1.md', api:'google'}) 22 | results = results.map(x =>x.text) 23 | t.is(results.length, 0) 24 | }) 25 | 26 | test.serial('translate absolute file from zh to en', async t =>{ 27 | let results = await translate({'aFile':__dirname+'/feature/testWrite1.md',tF:'en',tT:'zh'}) 28 | results = results.map(x =>x.text) 29 | t.is(results.length, 0) 30 | }) 31 | 32 | test.serial('translate absolute folder auto', async t =>{ 33 | let results = await translate([path.resolve(__dirname,'../md/'),'google','en','zh'], 'info') 34 | results = results.map(x =>x.text) 35 | t.is(results.length,0) 36 | }) 37 | 38 | // test.serial('translate absolute big folder auto', async t =>{ 39 | // let results = await translate([`*******/You_Don\'t\ _Know_JS/You-Dont-Know-JS`,'baidu'], 'verbose') 40 | // t.is(results.length,5) 41 | // }) 42 | -------------------------------------------------------------------------------- /test/setObjectKey.test.js: -------------------------------------------------------------------------------- 1 | const { test } = require('ava') 2 | const fs = require('fs') 3 | const [tree, truetree ] = require('./setObjectKey.Object.js') 4 | const {setObjectKey, translateValue} = require('../src/setObjectKey.js') 5 | var newObject = (oldObject) =>JSON.parse(JSON.stringify(oldObject)); 6 | 7 | let opts = (api) =>newObject({api,name:'test.md'}) 8 | 9 | test(' test baidu',async t =>{ 10 | let newTree = await setObjectKey(newObject(tree), opts('baidu')) 11 | delete newTree.Error 12 | t.true(!!newTree) 13 | }) 14 | 15 | test(' test youdao',async t =>{ 16 | let newTree = await setObjectKey(newObject(tree), opts('youdao')) 17 | delete newTree.Error 18 | t.true(!!newTree) 19 | }) 20 | 21 | test(' test google',async t =>{ 22 | let newTree = await setObjectKey(newObject(tree), opts('google')) 23 | delete newTree.Error 24 | t.true(!!newTree) 25 | }) 26 | 27 | test(' test translate type:asdf + html',async t =>{ 28 | let source = {type:'asdf',"value":"hello","child":{ 29 | "type": "html", 30 | "value": "" 31 | }} 32 | let value = {type:'asdf',"value":"你好","child":{ 33 | "type": "html", 34 | "value": "" 35 | }} 36 | let v = await setObjectKey(newObject(source), opts('baidu')) 37 | t.deepEqual(v,value) 38 | }) 39 | 40 | test(' test translate no key == value ',async t =>{ 41 | let noValue = await setObjectKey(newObject({type:'asdf'}), opts('baidu')) 42 | t.is(noValue,'no value') 43 | }) 44 | 45 | test(' test translate code or html false',async t =>{ 46 | let noValue = await setObjectKey(newObject({ 47 | "type": "html", 48 | "value": "" 49 | }), opts('baidu')) 50 | t.is(noValue,'no value') 51 | }) 52 | 53 | test.serial(' test translateValue ',async t =>{ 54 | let value = ['hello world'] 55 | let result = await translateValue(value, 'google').catch(e =>{ 56 | return [e] 57 | }) 58 | t.is(result.length,1) 59 | }) 60 | -------------------------------------------------------------------------------- /test/Fix/lengthEqual.test.js: -------------------------------------------------------------------------------- 1 | const { test } = require('ava') 2 | const fs = require('fs') 3 | 4 | const { translateLengthEquals, mergeAndCut } = require('../../src/Fix/lengthEqual.js') 5 | 6 | test("mergeAndCut String asdf", t =>{ 7 | let a =["a","b","c","d","e","f","g"] 8 | mergeAndCut(a, 2, 2, 5) 9 | t.deepEqual(a, ["a", "b", "cde", "f", "g"]) 10 | }) 11 | 12 | test("mergeAndCut String single", t =>{ 13 | let a =["asdf. ", "asdf. "] 14 | mergeAndCut(a, 0, 2, 1) 15 | t.deepEqual(a, ["asdf. asdf. "]) 16 | }) 17 | 18 | test("translateLengthEquals String long", t =>{ 19 | let a =[`excited. This an awesome (rigorous and respectful) and curated (I read every suggestion and make judgement calls) list of cold showers on overhyped topics. This does `] 20 | let b = ["1","2","4"] 21 | translateLengthEquals(a, b) 22 | t.is(b.length, 1) 23 | }) 24 | 25 | test("translateLengthEquals String with \' or \" ", t =>{ 26 | let a =[`"excited. This an awesome (rigorous and respectful) and curated (I read every suggestion and make judgement calls) list of cold showers on overhyped topics. This does "`] 27 | let b = ["1","2","3","4"] 28 | translateLengthEquals(a, b) 29 | t.is(b.length, 4) 30 | }) 31 | 32 | test("translateLengthEquals String with \' or \" has space", t =>{ 33 | let a =[` "excited. This an awesome (rigorous and respectful) and curated (I read every suggestion and make judgement calls) list of cold showers on overhyped topics. This does "`] 34 | let b = ["1","2","3","4"] 35 | translateLengthEquals(a, b) 36 | t.is(b.length, 4) 37 | }) 38 | 39 | test("translateLengthEquals with '. '", t =>{ 40 | let b =["asdf. asdf. . "] 41 | let c =["asdf. ", "asdf. ", ". "] 42 | translateLengthEquals(b, c) 43 | t.deepEqual(c, ["asdf. asdf. . "]) 44 | }) 45 | 46 | test("translateLengthEquals with '. ' and '!' ", t =>{ 47 | let b =["a,etc. sdf!. asdf. !"] 48 | let c =["asdf!", ". ", "asdf. ", "!"] 49 | translateLengthEquals(b, c) 50 | t.deepEqual(c, ["asdf!. asdf. !"]) 51 | }) 52 | 53 | test(`translateLengthEquals with '. ' and '。' `, t =>{ 54 | let b =[`asdf。. asdf. 。`,`asdf`] 55 | let c =[`asdf。`, `. `, `asdf. `, `。`, `asdf`] 56 | translateLengthEquals(b, c) 57 | t.deepEqual(c, b) 58 | }) 59 | 60 | -------------------------------------------------------------------------------- /src/typeSetAndGet.js: -------------------------------------------------------------------------------- 1 | const minimatch = require('minimatch'); 2 | 3 | const {getOptions} = require('./config/work-options.js') 4 | const configs = getOptions() 5 | const TYPES = configs['types'] 6 | const textGlob = configs['textGlob']; 7 | 8 | let types = ['html', 'code'].concat(TYPES) 9 | let sum = 0; 10 | 11 | function getTypeValue(obj,tranArray){ 12 | sum = 0; 13 | /** 14 | * @description Find ``obj['type'] === 'value'`` ,and``tranArray.push(obj[key])`` 15 | * @param {Object} obj 16 | * @param {String[]} tranArray 17 | * @returns {number} - find value number 18 | */ 19 | function deep(obj, tranArray) { 20 | Object.keys(obj).forEach(function (key) { 21 | 22 | // no translate code content 23 | if (obj['type'] && (types.some(t => obj['type'] == t))) { 24 | return sum 25 | } 26 | (obj[key] && typeof obj[key] === 'object') && deep(obj[key], tranArray) 27 | 28 | 29 | if (key === 'value' && obj[key].trim()) { 30 | // --text-glob {cli options} 31 | if(!textGlob || textGlob.every(g =>minimatch(obj[key],g))){ 32 | tranArray.push(obj[key]) 33 | sum++ 34 | } 35 | } 36 | }); 37 | return sum 38 | }; 39 | 40 | return deep(obj,tranArray) 41 | } 42 | function setTypeValue(obj, tranArrayZh){ 43 | /** 44 | * @description Find ``obj['type'] === 'value'``, and use ``tranArrayZh.shift`` set ``obj['value']`` 45 | * @param {any} obj - AST 46 | * @param {String[]} tranArrayZh 47 | * @returns 48 | */ 49 | function setdeep(obj, tranArrayZh) { 50 | Object.keys(obj).forEach(function (key) { 51 | 52 | if (obj['type'] && (types.some(t => obj['type'] == t))) { 53 | return sum 54 | } 55 | 56 | (obj[key] && typeof obj[key] === 'object') && setdeep(obj[key], tranArrayZh) 57 | 58 | if (key === 'value' && obj[key].trim()) { 59 | if (tranArrayZh.length) { 60 | if(!textGlob || textGlob.every(g =>minimatch(obj[key],g))){ 61 | obj[key] = tranArrayZh.shift() 62 | sum-- 63 | } 64 | } 65 | } 66 | }); 67 | return sum 68 | }; 69 | 70 | return setdeep(obj, tranArrayZh) 71 | } 72 | module.exports = { 73 | getTypeValue, 74 | setTypeValue 75 | } 76 | -------------------------------------------------------------------------------- /test/optionsTodo.test.js: -------------------------------------------------------------------------------- 1 | const { test } = require('ava') 2 | const fs = require('fs') 3 | let p = '../src/config/optionsTodo.js' 4 | const defaultArgs = { 5 | "logger": { 6 | "level": "verbose" 7 | }, 8 | "api":"baidu", 9 | "from":"en", 10 | "to":"zh", 11 | "num": 5, 12 | "rewrite": false 13 | } 14 | const {setDefault} = require(p) 15 | 16 | const rNobj =(obj) =>JSON.parse(JSON.stringify(obj)) 17 | 18 | test("setDefault",t=>{ 19 | function sum(a,b){return a+b} 20 | const s = setDefault(1, sum, 1) 21 | t.is(s,2) 22 | }) 23 | 24 | const {debugTodo} = require(p) 25 | 26 | test("debugTodo",t=>{ 27 | const s = debugTodo(true,rNobj(defaultArgs)) 28 | t.is(s, 'debug') 29 | const s2 = debugTodo('info',rNobj(defaultArgs)) 30 | t.is(s2,'info') 31 | }) 32 | 33 | const {matchAndSkip} = require(p) 34 | 35 | test("matchAndSkip",t=>{ 36 | const s = matchAndSkip({n:"info,nihao",type:'M'},rNobj(defaultArgs)) 37 | t.is(s.length, 2) 38 | const s2 = matchAndSkip({n:"info",type:'M'},rNobj(defaultArgs)) 39 | t.is(s2.length, 1) 40 | const s3 = matchAndSkip("",rNobj(defaultArgs)) 41 | t.is(s3.length, 0) 42 | }) 43 | 44 | const {typesTodo} = require(p) 45 | 46 | test("typesTodo",t=>{ 47 | const s = typesTodo({n:"info,nihao",type:'T'},rNobj(defaultArgs)) 48 | t.is(s.length, 2) 49 | }) 50 | 51 | const {fromTodo} = require(p) 52 | 53 | test("fromTodo",t=>{ 54 | const s = fromTodo('zh',rNobj(defaultArgs)) 55 | t.is(s,'zh') 56 | const s2 = fromTodo('',rNobj(defaultArgs)) 57 | t.is(s2,'en') 58 | }) 59 | const {toTodo} = require(p) 60 | 61 | test("toTodo",t=>{ 62 | const s = toTodo('ja',rNobj(defaultArgs)) 63 | t.is(s,'ja') 64 | const s2 = toTodo('',rNobj(defaultArgs)) 65 | t.is(s2,'zh') 66 | }) 67 | const {apiTodo} = require(p) 68 | 69 | test("apiTodo",t=>{ 70 | const s = apiTodo('',rNobj(defaultArgs)) 71 | t.is(s,'baidu') 72 | const s2 = apiTodo('google',rNobj(defaultArgs)) 73 | t.is(s2,'google') 74 | }) 75 | const {rewriteTodo} = require(p) 76 | 77 | test("rewriteTodo",t=>{ 78 | const one = rewriteTodo(true,rNobj(defaultArgs)) 79 | t.is(one,true) 80 | 81 | const two = rewriteTodo('google',rNobj(defaultArgs)) 82 | t.is(two,true) 83 | 84 | const three = rewriteTodo('',rNobj(defaultArgs)) 85 | t.is(three,false) 86 | }) 87 | const {numTodo} = require(p) 88 | 89 | test("numTodo",t=>{ 90 | const s = numTodo(10,rNobj(defaultArgs)) 91 | t.is(s,10) 92 | 93 | const s2 = numTodo('google',rNobj(defaultArgs)) 94 | t.is(s2,5) 95 | }) 96 | -------------------------------------------------------------------------------- /src/Fix/lengthEqual.js: -------------------------------------------------------------------------------- 1 | const {getOptions} = require('../config/work-options.js'); 2 | let configs = getOptions(); 3 | const {matchs, skips} = configs; 4 | const {tc} = require('../util/util.js'); 5 | 6 | let Equal; 7 | function translateLengthEquals(source, tranTxt) { 8 | let skipArr = ['... ', 'etc. ', 'i.e. ', 'e.g. '].concat(skips); 9 | let matchArr = ['. ', '! ', '; ', '!', '? ', '。'].concat(matchs); 10 | let trim = ["'", '"']; 11 | Equal = source.length; 12 | let newSource = [].concat(source); 13 | for (let i in source) { 14 | // typeof i == string 15 | // if(Equal == tranTxt.length) return 16 | 17 | source[i] = source[i].trim(); 18 | let idxStr = source[i]; 19 | if (trim.some(x => idxStr.startsWith(x) && idxStr.endsWith(x))) { 20 | // ' ** ' /" ** " 21 | } else { 22 | let howMany = 0; 23 | // let s = source[i] 24 | 25 | let thisMatch = matchArr.filter(m => idxStr.includes(m)); // just filter match string 26 | 27 | thisMatch.forEach(function(val) { 28 | while (idxStr.includes(val)) { 29 | let skipIndexs = []; 30 | 31 | skipArr.forEach(function(skip) { 32 | if (idxStr.includes(skip)) { 33 | skipIndexs.push(skip); 34 | } 35 | }); 36 | 37 | if (skipIndexs.length) { 38 | 39 | skipIndexs.forEach(skip => { 40 | idxStr = idxStr.replace(skip, tc.bgMagenta(`👌 `)); // over val 41 | }); 42 | 43 | continue; 44 | } else { 45 | if (idxStr.indexOf(val) + val.length == idxStr.length) { 46 | break; 47 | } 48 | 49 | idxStr = idxStr.replace(val, tc.bgRed(`🥄 `)); // over val 50 | howMany++; // how many ". "/ etc 51 | } 52 | } 53 | }); 54 | !!howMany && mergeAndCut(tranTxt, +i, howMany); // pay attion two + , string/number 55 | newSource[i] = idxStr; 56 | } 57 | } 58 | 59 | return newSource; 60 | } 61 | 62 | function mergeAndCut(Arr, index, howMany, TestLen) { 63 | let E = Equal || TestLen; 64 | let num = 0; 65 | // Merge howMany items to Index item 66 | for (let i = index; i < index + howMany; i++) { 67 | if (1 || Arr.length - num !== E) { 68 | Arr[i + 1] && (Arr[index] = Arr[index] + Arr[i + 1]); 69 | num++; 70 | } 71 | // else{ 72 | // break; 73 | // } 74 | } 75 | // splice Items : From the Index + 1 to ` i ` 76 | Arr.splice(index + 1, num); 77 | } 78 | 79 | module.exports = {translateLengthEquals, mergeAndCut}; 80 | -------------------------------------------------------------------------------- /md/1.zh.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Accented Characters in URLs 3 | linktitle: Accented Characters in URLs 4 | description: If you're having trouble with special characters in your taxonomies or titles adding odd characters to your URLs. 5 | date: 2017-02-01 6 | publishdate: 2017-02-01 7 | lastmod: 2017-02-01 8 | keywords: [urls,multilingual,special characters] 9 | categories: [troubleshooting] 10 | menu: 11 | docs: 12 | parent: "troubleshooting" 13 | weight: 14 | draft: false 15 | slug: 16 | aliases: [/troubleshooting/categories-with-accented-characters/] 17 | toc: true 18 | --- 19 | ## 问题: 带有重音字符的类别 20 | 21 | > 我的一个类别被命名为"乐卡尔",但链接最终是这样生成的: 22 | > 23 | > categories/le-carr%C3%A9 24 | > 25 | > 不工作. 我能忽略这个问题吗? 26 | 27 | ## 解决方案 28 | 29 | 你是一个MacOS的用户吗?如果是这样的话,你可能是一个受害者,HFS +文件系统的坚持来存储"é"(U + 00e9)字符正常形式分解(NFD)模式,即为"E"+"́"(U + 0065 + 0301). 30 | 31 | `勒% %`实际上是正确的,`% %`在U+ UTF-8版本00e9预期由Web服务器. 问题是OS X转了. [u + 00e9]进入之内[0065+0301+],从而`勒% %`不再工作. 相反,只有`勒卡雷连铸% 81`结束`81 %`将匹配[0065+0301+]最后. 32 | 33 | 这是OS X独有的. 世界上其他地方没有这样做,当然也不是你最可能运行Linux的Web服务器. 这也不是雨果特有的问题. 其他人在他们的HTML文件中有重音字符时就被这个咬了. 34 | 35 | 注意,这个问题并不具体于拉丁语脚本. 日本的Mac用户经常遇到相同的问题,例如`だ`分解成`た`和`与# x3099;`. (读[日本perl用户文章][]). 36 | 37 | rsync 3. x的救援!从[服务器故障的答案][]: 38 | 39 | > 你可以使用rsync的`ℴℴiconv`选择UTF-8 NFC与NFD之间转换,至少如果你的Mac. 有一个特别的`utf-8-mac`字符集是UTF-8 NFD. 因此,为了将文件从Mac复制到Web服务器,您需要运行类似于: 40 | > 41 | > `rsync -ℴℴiconv = utf-8-mac,UTF-8 localdir / mywebserver: remotedir /` 42 | > 43 | > 这会将所有本地文件名由UTF-8 NFD为NFC在远程服务器. 文件的内容不会受到影响. ℴ[服务器故障][] 44 | 45 | 请确保你有rsync 3的最新版本. 装X. rsync,OS X的船只已经过时. 即使是包装版本10.10(优诗美地国家公园)是版本2.6.9协议版本29. 这个`ℴℴiconv`国旗是新的rsync 3. X. 46 | 47 | ### 论坛参考 48 | 49 | - 50 | - [http://wiki.apache.org/subversion/nonnormalizingunicodecompositionawareness](http://wiki.apache.org/subversion/NonNormalizingUnicodeCompositionAwareness) 51 | - [http: / /恩. 维基百科. org /维基/ unicode_equivalence #例子](https://en.wikipedia.org/wiki/Unicode_equivalence#Example) 52 | - 53 | - 54 | 55 | [an answer posted on server fault]: http://serverfault.com/questions/397420/converting-utf-8-nfd-filenames-to-utf-8-nfc-in-either-rsync-or-afpd "Converting UTF-8 NFD filenames to UTF-8 NFC in either rsync or afpd, Server Fault Discussion" 56 | 57 | [japanese perl users article]: http://perl-users.jp/articles/advent-calendar/2010/english/24 "Encode::UTF8Mac makes you happy while handling file names on MacOSX" 58 | 59 | [server fault]: http://serverfault.com/questions/397420/converting-utf-8-nfd-filenames-to-utf-8-nfc-in-either-rsync-or-afpd "Converting UTF-8 NFD filenames to UTF-8 NFC in either rsync or afpd, Server Fault Discussion" 60 | -------------------------------------------------------------------------------- /md/about/aboutme/me.zh.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Accented Characters in URLs 3 | linktitle: Accented Characters in URLs 4 | description: If you're having trouble with special characters in your taxonomies or titles adding odd characters to your URLs. 5 | date: 2017-02-01 6 | publishdate: 2017-02-01 7 | lastmod: 2017-02-01 8 | keywords: [urls,multilingual,special characters] 9 | categories: [troubleshooting] 10 | menu: 11 | docs: 12 | parent: "troubleshooting" 13 | weight: 14 | draft: false 15 | slug: 16 | aliases: [/troubleshooting/categories-with-accented-characters/] 17 | toc: true 18 | --- 19 | ## 问题: 带有重音字符的类别 20 | 21 | > 我的一个类别被命名为"乐卡尔",但链接最终是这样生成的: 22 | > 23 | > categories/le-carr%C3%A9 24 | > 25 | > 不工作. 我能忽略这个问题吗? 26 | 27 | ## 解决方案 28 | 29 | 你是一个MacOS的用户吗?如果是这样的话,你可能是一个受害者,HFS +文件系统的坚持来存储"é"(U + 00e9)字符正常形式分解(NFD)模式,即为"E"+"́"(U + 0065 + 0301). 30 | 31 | `勒% %`实际上是正确的,`% %`在U+ UTF-8版本00e9预期由Web服务器. 问题是OS X转了. [u + 00e9]进入之内[0065+0301+],从而`勒% %`不再工作. 相反,只有`勒卡雷连铸% 81`结束`81 %`将匹配[0065+0301+]最后. 32 | 33 | 这是OS X独有的. 世界上其他地方没有这样做,当然也不是你最可能运行Linux的Web服务器. 这也不是雨果特有的问题. 其他人在他们的HTML文件中有重音字符时就被这个咬了. 34 | 35 | 注意,这个问题并不具体于拉丁语脚本. 日本的Mac用户经常遇到相同的问题,例如`だ`分解成`た`和`与# x3099;`. (读[日本perl用户文章][]). 36 | 37 | rsync 3. x的救援!从[服务器故障的答案][]: 38 | 39 | > 你可以使用rsync的`ℴℴiconv`选择UTF-8 NFC与NFD之间转换,至少如果你的Mac. 有一个特别的`utf-8-mac`字符集是UTF-8 NFD. 因此,为了将文件从Mac复制到Web服务器,您需要运行类似于: 40 | > 41 | > `rsync -ℴℴiconv = utf-8-mac,UTF-8 localdir / mywebserver: remotedir /` 42 | > 43 | > 这会将所有本地文件名由UTF-8 NFD为NFC在远程服务器. 文件的内容不会受到影响. ℴ[服务器故障][] 44 | 45 | 请确保你有rsync 3的最新版本. 装X. rsync,OS X的船只已经过时. 即使是包装版本10.10(优诗美地国家公园)是版本2.6.9协议版本29. 这个`ℴℴiconv`国旗是新的rsync 3. X. 46 | 47 | ### 论坛参考 48 | 49 | - 50 | - [http://wiki.apache.org/subversion/nonnormalizingunicodecompositionawareness](http://wiki.apache.org/subversion/NonNormalizingUnicodeCompositionAwareness) 51 | - [http: / /恩. 维基百科. org /维基/ unicode_equivalence #例子](https://en.wikipedia.org/wiki/Unicode_equivalence#Example) 52 | - 53 | - 54 | 55 | [an answer posted on server fault]: http://serverfault.com/questions/397420/converting-utf-8-nfd-filenames-to-utf-8-nfc-in-either-rsync-or-afpd "Converting UTF-8 NFD filenames to UTF-8 NFC in either rsync or afpd, Server Fault Discussion" 56 | 57 | [japanese perl users article]: http://perl-users.jp/articles/advent-calendar/2010/english/24 "Encode::UTF8Mac makes you happy while handling file names on MacOSX" 58 | 59 | [server fault]: http://serverfault.com/questions/397420/converting-utf-8-nfd-filenames-to-utf-8-nfc-in-either-rsync-or-afpd "Converting UTF-8 NFD filenames to UTF-8 NFC in either rsync or afpd, Server Fault Discussion" 60 | -------------------------------------------------------------------------------- /src/config/loggerConfig.js: -------------------------------------------------------------------------------- 1 | const winston = require('winston'); 2 | const ora = require("ora-min") 3 | 4 | // 获得日志等级 5 | const { 6 | getOptions 7 | } = require('./work-options.js') 8 | const configs = getOptions() 9 | 10 | var logger = new(winston.Logger)({ 11 | level: 'info', 12 | transports: [ 13 | new(winston.transports.Console)({ 14 | datePattern: '.yyyy-MM-ddTHH-mm', 15 | colorize: true 16 | }), 17 | new(winston.transports.File)({ 18 | filename: 'translate-info.log', 19 | handleExceptions: true, 20 | maxsize: 52000, 21 | maxFiles: 1, 22 | level: 'info', 23 | colorize: true 24 | }) 25 | ] 26 | }); 27 | 28 | logger.level = configs.logger.level 29 | 30 | let D = configs.logger.level === 'debug' 31 | 32 | // 日志接口 33 | 34 | let LOGGER; 35 | 36 | /** 37 | * @description start logger 38 | * @param {any} str 39 | * @param {string} level 40 | */ 41 | function loggerStart(str, level = 'debug'){ 42 | 43 | if (!D) { 44 | LOGGER = ora(str).start() 45 | } else { 46 | LOGGER = logger 47 | LOGGER[level](str) 48 | } 49 | } 50 | 51 | /** 52 | * @description set logger text 53 | * @param {String} str 54 | * @param {string} options.level 55 | * @param {string} options.color * 56 | */ 57 | function loggerText(str, options = {level:"debug",color:"green"}){ 58 | if(!LOGGER) return 59 | 60 | if (!D) { 61 | LOGGER.text = str 62 | if (options.color) { 63 | LOGGER.color = options.color 64 | } 65 | } else { 66 | str += '\n' 67 | if (options.level) { 68 | let level = options.level 69 | LOGGER[level](str) 70 | } 71 | } 72 | } 73 | 74 | /** 75 | * @description logger stop 76 | * @param {string} str 77 | * @param {string} options.ora 78 | * @param {string} options.level 79 | */ 80 | function loggerStop(str, options = {level:"debug"}){ 81 | if(!LOGGER){ 82 | return false 83 | } 84 | if (!D) { 85 | if (options.ora && str) { 86 | let ora = options.ora 87 | LOGGER[ora](str) 88 | } else { 89 | LOGGER.stop() 90 | } 91 | } else { 92 | if (str) { 93 | LOGGER[options.level](str) 94 | } 95 | } 96 | 97 | LOGGER = null 98 | 99 | } 100 | 101 | const getLogger = () =>{ 102 | return LOGGER 103 | } 104 | 105 | const _SETDEBUG = (d) =>{ 106 | D = d 107 | } 108 | 109 | function oneOra(str,end = 'succeed') { 110 | let l = getLogger() 111 | let oT; 112 | if(l && !D){ 113 | oT = l.text 114 | l.stop() 115 | } 116 | const s = ora(str).start() 117 | s.color = 'red' 118 | s[end]() 119 | 120 | if(l && !D){ 121 | loggerStart(oT) 122 | } 123 | } 124 | 125 | module.exports = { 126 | logger, 127 | loggerStart, 128 | loggerText, 129 | loggerStop, 130 | getLogger, 131 | _SETDEBUG, 132 | oneOra 133 | } 134 | -------------------------------------------------------------------------------- /test/setObjectKey.Object.js: -------------------------------------------------------------------------------- 1 | 2 | const { test } = require('ava') 3 | 4 | const tree = { 5 | "type": "root", 6 | "children": [ 7 | { 8 | "type": "heading", 9 | "depth": 2, 10 | "children": [ 11 | { 12 | "type": "text", 13 | "value": "1. InPath", 14 | "position": { 15 | "start": { 16 | "line": 1, 17 | "column": 4, 18 | "value": "Hello", 19 | "offset": 3 20 | }, 21 | "end": { 22 | "line": 1, 23 | "column": 9, 24 | "offset": 8 25 | }, 26 | "indent": [] 27 | } 28 | } 29 | ], 30 | "position": { 31 | "start": { 32 | "line": 1, 33 | "column": 1, 34 | "offset": 0 35 | }, 36 | "end": { 37 | "line": 1, 38 | "column": 9, 39 | "offset": 8 40 | }, 41 | "indent": [], 42 | "value": "2. OutPath" 43 | } 44 | } 45 | ], 46 | "position": { 47 | "start": { 48 | "line": 1, 49 | "column": 1, 50 | "offset": 0 51 | }, 52 | "end": { 53 | "line": 2, 54 | "column": 1, 55 | "offset": 9 56 | } 57 | } 58 | } 59 | 60 | 61 | 62 | const truetree = { 63 | "type": "root", 64 | "children": [ 65 | { 66 | "type": "heading", 67 | "depth": 2, 68 | "children": [ 69 | { 70 | "type": "text", 71 | "value": "1. InPath", 72 | "position": { 73 | "start": { 74 | "line": 1, 75 | "column": 4, 76 | "value": "你好", 77 | "offset": 3 78 | }, 79 | "end": { 80 | "line": 1, 81 | "column": 9, 82 | "offset": 8 83 | }, 84 | "indent": [] 85 | } 86 | } 87 | ], 88 | "position": { 89 | "start": { 90 | "line": 1, 91 | "column": 1, 92 | "offset": 0 93 | }, 94 | "end": { 95 | "line": 1, 96 | "column": 9, 97 | "offset": 8 98 | }, 99 | "indent": [], 100 | "value": "2. OutPath" 101 | } 102 | } 103 | ], 104 | "position": { 105 | "start": { 106 | "line": 1, 107 | "column": 1, 108 | "offset": 0 109 | }, 110 | "end": { 111 | "line": 2, 112 | "column": 1, 113 | "offset": 9 114 | } 115 | } 116 | } 117 | 118 | module.exports = [tree, truetree] 119 | -------------------------------------------------------------------------------- /src/config/optionsTodo.js: -------------------------------------------------------------------------------- 1 | // defaultConfig options 2 | /** 3 | * @description 4 | * @param {String|Boolean} option 5 | * @param {Function} callback 6 | * @param {any} args 7 | * @returns {Function} 8 | */ 9 | function setDefault(option, callback, args) { 10 | return callback(option, args); 11 | } 12 | 13 | /** 14 | * @description add match and skip Arr 15 | * @param {any} mS 16 | * @param {string} mS.n 17 | * @param {any} args 18 | */ 19 | function matchAndSkip(mS, args) { 20 | let BeArr = []; 21 | if (mS.n) { 22 | BeArr = BeArr.concat(mS.n.split(',')); 23 | } 24 | // init 25 | if (mS.type == 'M') { 26 | args.matchs = BeArr; 27 | } else { 28 | args.skips = BeArr; 29 | } 30 | return BeArr; 31 | } 32 | 33 | /** 34 | * @description add md AST types 35 | * @param {any} mS 36 | * @param {string} mS.n 37 | * @param {any} args 38 | */ 39 | function typesTodo(mS, args) { 40 | let BeArr = []; 41 | if (mS.n) { 42 | BeArr = BeArr.concat(mS.n.trim().split(',')); 43 | } 44 | // init 45 | if (mS.type == 'T') { 46 | args.types = BeArr; 47 | } 48 | return BeArr; 49 | } 50 | 51 | /** 52 | * @description 53 | * @param {String|Boolean} debug 54 | * @param {any} args 55 | * @returns {String} 56 | */ 57 | function debugTodo(debug, args) { 58 | if (debug) { 59 | args.logger.level = 'debug'; 60 | } 61 | if (typeof debug == 'string') { 62 | args.logger.level = debug; 63 | } 64 | return args.logger.level; 65 | } 66 | 67 | /** 68 | * @description 69 | * @param {String} tranFrom 70 | * @param {any} args 71 | * @returns {String} 72 | */ 73 | function fromTodo(tranFrom, args) { 74 | if (tranFrom) { 75 | args.from = tranFrom; 76 | } 77 | return args.from; 78 | } 79 | 80 | /** 81 | * @description 82 | * @param {String} tranTo 83 | * @param {any} args 84 | * @returns {String} 85 | */ 86 | function toTodo(tranTo, args) { 87 | if (tranTo) { 88 | args.to = tranTo; 89 | } 90 | return args.to; 91 | } 92 | 93 | /** 94 | * @description 95 | * @param {number} num 96 | * @param {any} args 97 | * @returns {number} 98 | */ 99 | function numTodo(num, args) { 100 | if (typeof num == 'number') { 101 | if (num > 0) { 102 | args.num = num; 103 | } 104 | } 105 | return args.num; 106 | } 107 | 108 | /** 109 | * @description api {``baidu | google | youdao``} 110 | * @param {String} api 111 | * @param {any} args 112 | * @returns {String} 113 | */ 114 | function apiTodo(api, args) { 115 | if (api) { 116 | args.api = api; 117 | } 118 | return args.api; 119 | } 120 | 121 | /** 122 | * @description 123 | * @param {Boolean} rewrite 124 | * @param {any} args 125 | * @returns {Boolean} 126 | */ 127 | function rewriteTodo(rewrite, args) { 128 | args.rewrite = rewrite ? true : false; 129 | return args.rewrite; 130 | } 131 | 132 | module.exports = { 133 | setDefault, 134 | debugTodo, 135 | fromTodo, 136 | toTodo, 137 | apiTodo, 138 | rewriteTodo, 139 | numTodo, 140 | matchAndSkip, 141 | typesTodo 142 | }; 143 | -------------------------------------------------------------------------------- /src/translateMds.js: -------------------------------------------------------------------------------- 1 | 'use script' 2 | const fs = require('mz/fs') 3 | const path = require('path') 4 | const remark = require('remark') 5 | 6 | const Listmd = require('./util/readmd.js') 7 | const cutMdhead = require('./util/cutMdhead.js') 8 | const { O2A } = require('./util/util.js') 9 | 10 | const { 11 | logger 12 | } = require('./config/loggerConfig.js') // winston config 13 | 14 | // config 15 | const mergeConfig = require('./config/mergeConfig') 16 | 17 | // Object to Array 18 | 19 | /** 20 | * @description translateMds main 21 | * @param {Array|Object} options 22 | * @param {Boolean|String} debug 23 | * @param {boolean} [isCli=false] 24 | * @returns {Array} results 25 | * @returns {String} results[i].text 26 | * @returns {String} results[i].error 27 | */ 28 | async function translateMds(options, debug, isCli = false) { 29 | 30 | let absoluteFile, api, tranFrom, tranTo 31 | if (!options) throw logger.error('options is NULL') 32 | 33 | // options is Array or Object 34 | if (options instanceof Array) { 35 | [absoluteFile, api, tranFrom, tranTo] = options 36 | } else if (options instanceof Object) { 37 | [absoluteFile, api, tranFrom, tranTo] = O2A(options) 38 | } 39 | // file is absolute 40 | if (!absoluteFile || !path.isAbsolute(absoluteFile)) { 41 | throw logger.error(`translateMds absoluteFile is no absolute ${absoluteFile}`) 42 | } 43 | // change defaultConfig from options 44 | // return first option 45 | if (!isCli) { 46 | let opts = { 47 | debug, 48 | tranFrom, 49 | tranTo, 50 | api, 51 | options 52 | }; 53 | 54 | let back = mergeConfig.main(opts) 55 | debug = back.debug 56 | tranFrom = back.tranFrom 57 | tranTo = back.tranTo 58 | api = back.api 59 | } 60 | 61 | // setObjectKey.js after rewrite config.json 62 | const { 63 | setObjectKey 64 | } = require('./setObjectKey.js') 65 | 66 | async function t(data,opts) { 67 | 68 | let head, body, mdAst,translateMdAst 69 | [body, head] = cutMdhead(data) 70 | 71 | // to AST 72 | mdAst = remark.parse(body) 73 | 74 | // translate Array 75 | translateMdAst = await setObjectKey(mdAst, opts) 76 | 77 | if (typeof translateMdAst !== 'string') { 78 | let E = translateMdAst.Error 79 | // Ast to markdown 80 | body = remark().use({ 81 | settings: {commonmark: true, emphasis: '*', strong: '*', fences: true, paddedTable: false} 82 | }).stringify(translateMdAst) 83 | 84 | return [head+body, E] 85 | } 86 | 87 | return ['',translateMdAst] 88 | } 89 | 90 | let results = [] 91 | 92 | // get floder markdown files Array 93 | const getList = isCli ? [absoluteFile] : await Listmd(absoluteFile, {deep:'all'}) 94 | for (i in getList) { 95 | let value = getList[i] 96 | 97 | // 去掉 .**.zh 的后缀 和 自己本身 .match(/\.[a-zA-Z]+\.md+/) 98 | if(isCli){ 99 | 100 | }else{ 101 | if ( value.endsWith(`.${tranTo}.md`) || value.match(/\.[a-zA-Z]+\.md+/) || !value.endsWith('.md')){ 102 | continue 103 | } 104 | const {insert_flg } = require('./util/util.js') 105 | 106 | if ( fs.existsSync( insert_flg(value,`.${tranTo}`, 3 ))){ 107 | continue 108 | } 109 | } 110 | 111 | let readfile = await fs.readFile(value, 'utf8') 112 | 113 | let E 114 | let _translate = await t(readfile,{name:value,api}).then(x => { 115 | E = x[1] 116 | return x[0] 117 | }).catch(x => { 118 | E = x 119 | return '' 120 | }) 121 | results.push({text:_translate, error:E}) 122 | } 123 | 124 | return results 125 | } 126 | 127 | 128 | module.exports = translateMds 129 | -------------------------------------------------------------------------------- /md/1.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Accented Characters in URLs 3 | linktitle: Accented Characters in URLs 4 | description: If you're having trouble with special characters in your taxonomies or titles adding odd characters to your URLs. 5 | date: 2017-02-01 6 | publishdate: 2017-02-01 7 | lastmod: 2017-02-01 8 | keywords: [urls,multilingual,special characters] 9 | categories: [troubleshooting] 10 | menu: 11 | docs: 12 | parent: "troubleshooting" 13 | weight: 14 | draft: false 15 | slug: 16 | aliases: [/troubleshooting/categories-with-accented-characters/] 17 | toc: true 18 | --- 19 | 20 | ## Trouble: Categories with accented characters 21 | 22 | > One of my categories is named "Le-carré," but the link ends up being generated like this: 23 | > 24 | > ``` 25 | > categories/le-carr%C3%A9 26 | > ``` 27 | > 28 | > And not working. Is there an easy fix for this that I'm overlooking? 29 | 30 | ## Solution 31 | 32 | Are you a macOS user? If so, you are likely a victim of HFS Plus file system's insistence to store the "é" (U+00E9) character in Normal Form Decomposed (NFD) mode, i.e. as "e" + " ́" (U+0065 U+0301). 33 | 34 | `le-carr%C3%A9` is actually correct, `%C3%A9` being the UTF-8 version of U+00E9 as expected by the web server. The problem is that OS X turns [U+00E9] into [U+0065 U+0301], and thus `le-carr%C3%A9` no longer works. Instead, only `le-carre%CC%81` ending with `e%CC%81` would match that [U+0065 U+0301] at the end. 35 | 36 | This is unique to OS X. The rest of the world does not do this, and most certainly not your web server which is most likely running Linux. This is not a Hugo-specific problem either. Other people have been bitten by this when they have accented characters in their HTML files. 37 | 38 | Note that this problem is not specific to Latin scripts. Japanese Mac users often run into the same issue; e.g., with `だ` decomposing into `た` and `゙`. (Read the [Japanese Perl users article][]). 39 | 40 | Rsync 3.x to the rescue! From [an answer posted on Server Fault][]: 41 | 42 | > You can use rsync's `--iconv` option to convert between UTF-8 NFC & NFD, at least if you're on a Mac. There is a special `utf-8-mac` character set that stands for UTF-8 NFD. So to copy files from your Mac to your web server, you'd need to run something like: 43 | > 44 | > `rsync -a --iconv=utf-8-mac,utf-8 localdir/ mywebserver:remotedir/` 45 | > 46 | > This will convert all the local filenames from UTF-8 NFD to UTF-8 NFC on the remote server. The files' contents won't be affected. - [Server Fault][] 47 | 48 | Please make sure you have the latest version of rsync 3.x installed. The rsync that ships with OS X is outdated. Even the version that comes packaged with 10.10 (Yosemite) is version 2.6.9 protocol version 29. The `--iconv` flag is new in rsync 3.x. 49 | 50 | ### Discussion Forum References 51 | 52 | * http://discourse.gohugo.io/t/categories-with-accented-characters/505 53 | * http://wiki.apache.org/subversion/NonNormalizingUnicodeCompositionAwareness 54 | * https://en.wikipedia.org/wiki/Unicode_equivalence#Example 55 | * http://zaiste.net/2012/07/brand_new_rsync_for_osx/ 56 | * https://gogo244.wordpress.com/2014/09/17/drived-me-crazy-convert-utf-8-mac-to-utf-8/ 57 | 58 | [an Answer posted on Server Fault]: http://serverfault.com/questions/397420/converting-utf-8-nfd-filenames-to-utf-8-nfc-in-either-rsync-or-afpd "Converting UTF-8 NFD filenames to UTF-8 NFC in either rsync or afpd, Server Fault Discussion" 59 | [Japanese Perl users article]: http://perl-users.jp/articles/advent-calendar/2010/english/24 "Encode::UTF8Mac makes you happy while handling file names on MacOSX" 60 | [Server Fault]: http://serverfault.com/questions/397420/converting-utf-8-nfd-filenames-to-utf-8-nfc-in-either-rsync-or-afpd "Converting UTF-8 NFD filenames to UTF-8 NFC in either rsync or afpd, Server Fault Discussion" 61 | -------------------------------------------------------------------------------- /md/about/aboutme/me.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Accented Characters in URLs 3 | linktitle: Accented Characters in URLs 4 | description: If you're having trouble with special characters in your taxonomies or titles adding odd characters to your URLs. 5 | date: 2017-02-01 6 | publishdate: 2017-02-01 7 | lastmod: 2017-02-01 8 | keywords: [urls,multilingual,special characters] 9 | categories: [troubleshooting] 10 | menu: 11 | docs: 12 | parent: "troubleshooting" 13 | weight: 14 | draft: false 15 | slug: 16 | aliases: [/troubleshooting/categories-with-accented-characters/] 17 | toc: true 18 | --- 19 | 20 | ## Trouble: Categories with accented characters 21 | 22 | > One of my categories is named "Le-carré," but the link ends up being generated like this: 23 | > 24 | > ``` 25 | > categories/le-carr%C3%A9 26 | > ``` 27 | > 28 | > And not working. Is there an easy fix for this that I'm overlooking? 29 | 30 | ## Solution 31 | 32 | Are you a macOS user? If so, you are likely a victim of HFS Plus file system's insistence to store the "é" (U+00E9) character in Normal Form Decomposed (NFD) mode, i.e. as "e" + " ́" (U+0065 U+0301). 33 | 34 | `le-carr%C3%A9` is actually correct, `%C3%A9` being the UTF-8 version of U+00E9 as expected by the web server. The problem is that OS X turns [U+00E9] into [U+0065 U+0301], and thus `le-carr%C3%A9` no longer works. Instead, only `le-carre%CC%81` ending with `e%CC%81` would match that [U+0065 U+0301] at the end. 35 | 36 | This is unique to OS X. The rest of the world does not do this, and most certainly not your web server which is most likely running Linux. This is not a Hugo-specific problem either. Other people have been bitten by this when they have accented characters in their HTML files. 37 | 38 | Note that this problem is not specific to Latin scripts. Japanese Mac users often run into the same issue; e.g., with `だ` decomposing into `た` and `゙`. (Read the [Japanese Perl users article][]). 39 | 40 | Rsync 3.x to the rescue! From [an answer posted on Server Fault][]: 41 | 42 | > You can use rsync's `--iconv` option to convert between UTF-8 NFC & NFD, at least if you're on a Mac. There is a special `utf-8-mac` character set that stands for UTF-8 NFD. So to copy files from your Mac to your web server, you'd need to run something like: 43 | > 44 | > `rsync -a --iconv=utf-8-mac,utf-8 localdir/ mywebserver:remotedir/` 45 | > 46 | > This will convert all the local filenames from UTF-8 NFD to UTF-8 NFC on the remote server. The files' contents won't be affected. - [Server Fault][] 47 | 48 | Please make sure you have the latest version of rsync 3.x installed. The rsync that ships with OS X is outdated. Even the version that comes packaged with 10.10 (Yosemite) is version 2.6.9 protocol version 29. The `--iconv` flag is new in rsync 3.x. 49 | 50 | ### Discussion Forum References 51 | 52 | * http://discourse.gohugo.io/t/categories-with-accented-characters/505 53 | * http://wiki.apache.org/subversion/NonNormalizingUnicodeCompositionAwareness 54 | * https://en.wikipedia.org/wiki/Unicode_equivalence#Example 55 | * http://zaiste.net/2012/07/brand_new_rsync_for_osx/ 56 | * https://gogo244.wordpress.com/2014/09/17/drived-me-crazy-convert-utf-8-mac-to-utf-8/ 57 | 58 | [an Answer posted on Server Fault]: http://serverfault.com/questions/397420/converting-utf-8-nfd-filenames-to-utf-8-nfc-in-either-rsync-or-afpd "Converting UTF-8 NFD filenames to UTF-8 NFC in either rsync or afpd, Server Fault Discussion" 59 | [Japanese Perl users article]: http://perl-users.jp/articles/advent-calendar/2010/english/24 "Encode::UTF8Mac makes you happy while handling file names on MacOSX" 60 | [Server Fault]: http://serverfault.com/questions/397420/converting-utf-8-nfd-filenames-to-utf-8-nfc-in-either-rsync-or-afpd "Converting UTF-8 NFD filenames to UTF-8 NFC in either rsync or afpd, Server Fault Discussion" 61 | -------------------------------------------------------------------------------- /test/cutMdhead.test.js: -------------------------------------------------------------------------------- 1 | const { test } = require('ava') 2 | const fs = require('fs') 3 | 4 | const cut = require('../src/util/cutMdhead.js') 5 | 6 | test("cut --- head", t =>{ 7 | let [body, head] = cut(beforedata) 8 | t.is(body, afterdata) 9 | t.is(head, onlyhead) 10 | }) 11 | 12 | test("cut +++ head", t =>{ 13 | let [body, head] = cut(beforedata2) 14 | t.is(body, afterdata2) 15 | t.is(head, onlyhead2) 16 | }) 17 | 18 | test(" no cut ", t =>{ 19 | let [body, head] = cut("# 你好") 20 | t.is(body,"# 你好") 21 | t.is(head, "") 22 | }) 23 | 24 | let onlyhead = `--- 25 | title: Hugo Documentation 26 | linktitle: Hugo 27 | description: Hugo is the world's fastest static website engine. It's written in Go (aka Golang) and developed by bep, spf13 and friends. 28 | date: 2017-02-01 29 | publishdate: 2017-02-01 30 | lastmod: 2017-02-01 31 | menu: 32 | main: 33 | parent: "section name" 34 | weight: 01 35 | weight: 01 #rem 36 | draft: false 37 | slug: 38 | aliases: [] 39 | toc: false 40 | layout: documentation-home 41 | ---\n\n` 42 | 43 | let afterdata = ` 44 | 45 | Hugo is the **world's fastest static website engine.** It's written in Go (aka Golang) and developed by [bep](https://github.com/bep), [spf13](https://github.com/spf13) and [friends](https://github.com/gohugoio/hugo/graphs/contributors). Below you will find some of the most common and helpful pages from our documentation. 46 | ➜ /Users/lizhenyong/Desk` 47 | 48 | let beforedata = `--- 49 | title: Hugo Documentation 50 | linktitle: Hugo 51 | description: Hugo is the world's fastest static website engine. It's written in Go (aka Golang) and developed by bep, spf13 and friends. 52 | date: 2017-02-01 53 | publishdate: 2017-02-01 54 | lastmod: 2017-02-01 55 | menu: 56 | main: 57 | parent: "section name" 58 | weight: 01 59 | weight: 01 #rem 60 | draft: false 61 | slug: 62 | aliases: [] 63 | toc: false 64 | layout: documentation-home 65 | --- 66 | 67 | Hugo is the **world's fastest static website engine.** It's written in Go (aka Golang) and developed by [bep](https://github.com/bep), [spf13](https://github.com/spf13) and [friends](https://github.com/gohugoio/hugo/graphs/contributors). Below you will find some of the most common and helpful pages from our documentation. 68 | ➜ /Users/lizhenyong/Desk` 69 | 70 | let onlyhead2 = `+++ 71 | title: Hugo Documentation 72 | linktitle: Hugo 73 | description: Hugo is the world's fastest static website engine. It's written in Go (aka Golang) and developed by bep, spf13 and friends. 74 | date: 2017-02-01 75 | publishdate: 2017-02-01 76 | lastmod: 2017-02-01 77 | menu: 78 | main: 79 | parent: "section name" 80 | weight: 01 81 | weight: 01 #rem 82 | draft: false 83 | slug: 84 | aliases: [] 85 | toc: false 86 | layout: documentation-home 87 | +++\n\n` 88 | 89 | let afterdata2 = ` 90 | 91 | Hugo is the **world's fastest static website engine.** It's written in Go (aka Golang) and developed by [bep](https://github.com/bep), [spf13](https://github.com/spf13) and [friends](https://github.com/gohugoio/hugo/graphs/contributors). Below you will find some of the most common and helpful pages from our documentation. 92 | ➜ /Users/lizhenyong/Desk` 93 | 94 | let beforedata2 = `+++ 95 | title: Hugo Documentation 96 | linktitle: Hugo 97 | description: Hugo is the world's fastest static website engine. It's written in Go (aka Golang) and developed by bep, spf13 and friends. 98 | date: 2017-02-01 99 | publishdate: 2017-02-01 100 | lastmod: 2017-02-01 101 | menu: 102 | main: 103 | parent: "section name" 104 | weight: 01 105 | weight: 01 #rem 106 | draft: false 107 | slug: 108 | aliases: [] 109 | toc: false 110 | layout: documentation-home 111 | +++ 112 | 113 | Hugo is the **world's fastest static website engine.** It's written in Go (aka Golang) and developed by [bep](https://github.com/bep), [spf13](https://github.com/spf13) and [friends](https://github.com/gohugoio/hugo/graphs/contributors). Below you will find some of the most common and helpful pages from our documentation. 114 | ➜ /Users/lizhenyong/Desk` 115 | -------------------------------------------------------------------------------- /src/config/mergeConfig.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const { 3 | setDefault, 4 | debugTodo, 5 | fromTodo, 6 | toTodo, 7 | apiTodo, 8 | rewriteTodo, 9 | numTodo, 10 | matchAndSkip, 11 | typesTodo 12 | } = require('./optionsTodo.js') 13 | let workOptions = require('./work-options') 14 | 15 | function mergeConfig(cli) { 16 | let defaultConfig = workOptions.getOptions() 17 | 18 | let debug = setDefault(cli.flags['D'], debugTodo, defaultConfig) 19 | let tranFr = setDefault(cli.flags['f'], fromTodo, defaultConfig) 20 | let tranTo = setDefault(cli.flags['t'], toTodo, defaultConfig) 21 | let api = setDefault(cli.flags['a'], apiTodo, defaultConfig) 22 | let rewrite = setDefault(cli.flags['R'], rewriteTodo, defaultConfig) 23 | let asyncNum = setDefault(cli.flags['N'], numTodo, defaultConfig) 24 | 25 | setDefault({ 26 | n: cli.flags['M'], 27 | type: 'M' 28 | }, matchAndSkip, defaultConfig) 29 | setDefault({ 30 | n: cli.flags['S'], 31 | type: 'S' 32 | }, matchAndSkip, defaultConfig) 33 | setDefault({ 34 | n: cli.flags['T'], 35 | type: 'T' 36 | }, typesTodo, defaultConfig) 37 | 38 | let Force = cli.flags['F'] ? true : false 39 | if(Force){ 40 | defaultConfig.force = Force 41 | } 42 | 43 | let COM = cli.flags['G'] ? true : false 44 | if(COM){ 45 | defaultConfig.com = COM 46 | } 47 | 48 | let Cache = cli.flags['C'] ? true : false 49 | if(Cache){ 50 | defaultConfig.cache = Cache 51 | } 52 | 53 | let values = cli.flags['values'] 54 | if(values){ 55 | defaultConfig.getvalues = (typeof values === 'string') ? path.resolve(values) : path.resolve('./translate-values.md') 56 | } 57 | 58 | let translate = cli.flags['translate'] 59 | if(typeof translate === 'string'){ 60 | defaultConfig.translate = path.resolve(translate) 61 | } 62 | 63 | let wait = cli.flags['timewait'] 64 | if(wait && !isNaN(+wait)){ 65 | defaultConfig.timewait = wait 66 | } 67 | 68 | let ignores = cli.flags['ignore'] 69 | if(typeof ignores === 'string'){ 70 | ignores = ignores.split(',') 71 | }else{ 72 | ignores = false 73 | } 74 | defaultConfig.ignore = ignores 75 | 76 | let glob = cli.flags['glob'] 77 | if(typeof glob === 'string'){ 78 | glob = glob.split(',') 79 | }else{ 80 | glob = false 81 | } 82 | defaultConfig.glob = glob 83 | 84 | let textGlob = cli.flags['textGlob'] 85 | if(typeof textGlob === 'string'){ 86 | textGlob = textGlob.split(',') 87 | }else{ 88 | textGlob = false 89 | } 90 | defaultConfig.textGlob = textGlob 91 | 92 | // disk 93 | defaultConfig.disk = cli.flags['disk'] == undefined 94 | // zh symbal 95 | defaultConfig.zh = cli.flags['zh'] == undefined 96 | 97 | let cacheName = cli.flags['cacheName'] 98 | if(typeof cacheName === 'string'){ 99 | defaultConfig.cacheName = cacheName 100 | } 101 | 102 | workOptions.setOptions(defaultConfig) 103 | console.log(cli.flags) 104 | return { 105 | debug, 106 | tranFr, 107 | tranTo, 108 | api, 109 | rewrite, 110 | asyncNum, 111 | Force, 112 | ignores, 113 | glob, 114 | Cache 115 | } 116 | } 117 | 118 | function main(opts) { 119 | let defaultConfig = workOptions.getOptions() 120 | 121 | let { 122 | debug, 123 | tranFrom, 124 | tranTo, 125 | api, 126 | options 127 | } = opts 128 | 129 | debug = setDefault(debug, debugTodo, defaultConfig) 130 | tranFrom = setDefault(tranFrom, fromTodo, defaultConfig) 131 | tranTo = setDefault(tranTo, toTodo, defaultConfig) 132 | api = setDefault(api, apiTodo, defaultConfig) 133 | 134 | setDefault({ 135 | n: options.Matchs, 136 | type: 'M' 137 | }, matchAndSkip, defaultConfig) 138 | setDefault({ 139 | n: options.Skips, 140 | type: 'S' 141 | }, matchAndSkip, defaultConfig) 142 | setDefault({ 143 | n: options.Types, 144 | type: 'T' 145 | }, typesTodo, defaultConfig) 146 | // rewrite config.json 147 | workOptions.setOptions(defaultConfig) 148 | 149 | return { 150 | debug, 151 | tranFrom, 152 | tranTo, 153 | api 154 | } 155 | } 156 | 157 | 158 | exports = module.exports = mergeConfig 159 | exports.main = main 160 | -------------------------------------------------------------------------------- /NodePathdata.json: -------------------------------------------------------------------------------- 1 | { 2 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/cli.js": [ 3 | "update-notifier", 4 | "what-time", 5 | "minimatch", 6 | "async", 7 | "fs", 8 | "path", 9 | "./src/util/readmd.js", 10 | "meow", 11 | "./src/config/mergeConfig.js", 12 | "./src/util/util.js", 13 | "./src/translateMds.js", 14 | "./src/config/loggerConfig.js", 15 | "./src/util/writeDataToFile.js" 16 | ], 17 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/src/util/readmd.js": [ 18 | "files-list" 19 | ], 20 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/src/config/mergeConfig.js": [ 21 | "path", 22 | "./optionsTodo.js", 23 | "./work-options" 24 | ], 25 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/src/config/work-options.js": [ 26 | "./defaultConfig.json" 27 | ], 28 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/src/util/util.js": [ 29 | "turbocolor", 30 | "path", 31 | "mz/fs" 32 | ], 33 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/src/translateMds.js": [ 34 | "mz/fs", 35 | "path", 36 | "remark", 37 | "./util/readmd.js", 38 | "./util/cutMdhead.js", 39 | "./util/util.js", 40 | "./config/loggerConfig.js", 41 | "./config/mergeConfig", 42 | "./setObjectKey.js", 43 | "./util/util.js" 44 | ], 45 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/src/config/loggerConfig.js": [ 46 | "winston", 47 | "ora-min", 48 | "./work-options.js" 49 | ], 50 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/src/setObjectKey.js": [ 51 | "translation.js-fix", 52 | "./config/loggerConfig.js", 53 | "./config/work-options.js", 54 | "./util/diskCache", 55 | "./Fix/fixZhtoEn.js", 56 | "./Fix/lengthEqual.js", 57 | "./Fix/fixFileTooBig.js", 58 | "./util/util.js", 59 | "./util/debugMsg.js", 60 | "./typeSetAndGet" 61 | ], 62 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/src/util/diskCache.js": [ 63 | "diskdb", 64 | "path" 65 | ], 66 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/src/Fix/fixZhtoEn.js": [ 67 | "zh-to-en-symbol" 68 | ], 69 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/src/Fix/lengthEqual.js": [ 70 | "../config/work-options.js", 71 | "../util/util.js" 72 | ], 73 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/src/util/debugMsg.js": [ 74 | "debug')('mds:tran", 75 | "./util.js", 76 | "../config/loggerConfig.js" 77 | ], 78 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/src/typeSetAndGet.js": [ 79 | "minimatch", 80 | "./config/work-options.js" 81 | ], 82 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/src/util/writeDataToFile.js": [ 83 | "fs", 84 | "./util", 85 | "../config/loggerConfig.js", 86 | "../config/work-options.js" 87 | ], 88 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/test/cli.test.js": [ 89 | "ava", 90 | "path", 91 | "execa", 92 | "../package" 93 | ], 94 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/test/cutMdhead.test.js": [ 95 | "ava", 96 | "fs", 97 | "../src/util/cutMdhead.js" 98 | ], 99 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/test/mergeConfig.js": [ 100 | "ava", 101 | "../src/config/mergeConfig" 102 | ], 103 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/test/optionsTodo.test.js": [ 104 | "ava", 105 | "fs" 106 | ], 107 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/test/readmd.test.js": [ 108 | "ava", 109 | "../src/util/readmd.js" 110 | ], 111 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/test/setObjectKey.Object.js": [ 112 | "ava" 113 | ], 114 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/test/setObjectKey.test.js": [ 115 | "ava", 116 | "fs", 117 | "./setObjectKey.Object.js", 118 | "../src/setObjectKey.js" 119 | ], 120 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/test/translateExports.test.js": [ 121 | "ava", 122 | "path", 123 | "../src/translateMds.js" 124 | ], 125 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/test/writeDataToFile.test.js": [ 126 | "ava", 127 | "fs", 128 | "../src/util/writeDataToFile.js", 129 | "../src/util/util.js" 130 | ], 131 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/test/Fix/fixFileTooBig.test.js": [ 132 | "ava", 133 | "fs", 134 | "../../src/Fix/fixFileTooBig.js" 135 | ], 136 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/test/Fix/lengthEqual.test.js": [ 137 | "ava", 138 | "fs", 139 | "../../src/Fix/lengthEqual.js" 140 | ], 141 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/test/disk-cache/disk.js": [ 142 | "ava", 143 | "../../src/util/diskCache" 144 | ], 145 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/test/logger/debugMgs.test.js": [ 146 | "ava", 147 | "../../src/util/debugMsg", 148 | "debug')('mds:tran", 149 | "../../src/config/loggerConfig.js" 150 | ], 151 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/test/logger/logger.test.js": [ 152 | "ava", 153 | "../../src/config/loggerConfig" 154 | ], 155 | "/Users/lizhenyong/Desktop/JSJSJSJSJSJJSJS——project/node/translate-mds/test/translate-file/values.test.js": [ 156 | "ava", 157 | "path", 158 | "execa" 159 | ] 160 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # translate .md to \*.md [![explain](http://llever.com/explain.svg)](https://github.com/chinanf-boy/explain-translateMds) [![install size](https://packagephobia.now.sh/badge?p=translate-mds)](https://packagephobia.now.sh/result?p=translate-mds) 2 | 3 | like 4 | 5 | ```bash 6 | .md to .「all-language」.md 7 | ``` 8 | 9 | [english](./README.en.md) 10 | 11 | --- 12 | 13 | [![Build Status](https://travis-ci.org/chinanf-boy/translate-mds.svg?branch=master)](https://travis-ci.org/chinanf-boy/translate-mds) 14 | [![codecov](https://codecov.io/gh/chinanf-boy/translate-mds/branch/master/graph/badge.svg)](https://codecov.io/gh/chinanf-boy/translate-mds) 15 | [![GitHub license](https://img.shields.io/github/license/chinanf-boy/translate-mds.svg)](https://github.com/chinanf-boy/translate-mds/blob/master/License) 16 | ![npm](https://img.shields.io/npm/v/translate-mds.svg) 17 | ![GitHub release](https://img.shields.io/github/tag/chinanf-boy/translate-mds.svg) 18 | 19 | ## 生活 20 | 21 | [help me live , live need money 💰](https://github.com/chinanf-boy/live-need-money) 22 | 23 | --- 24 | 25 | 26 | 27 | 28 | - [这个项目是 为了 所有-的-markdown-编写-文件 📃 翻译 的 `工具`](#%E8%BF%99%E4%B8%AA%E9%A1%B9%E7%9B%AE%E6%98%AF-%E4%B8%BA%E4%BA%86-%E6%89%80%E6%9C%89-%E7%9A%84-markdown-%E7%BC%96%E5%86%99-%E6%96%87%E4%BB%B6--%E7%BF%BB%E8%AF%91-%E7%9A%84-%E5%B7%A5%E5%85%B7) 29 | - [Demo](#demo) 30 | - [命令行选项](#%E5%91%BD%E4%BB%A4%E8%A1%8C%E9%80%89%E9%A1%B9) 31 | - [My-translate-list](#my-translate-list) 32 | - [常见问题](#%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98) 33 | - [1. 有时会抽风会卡住,停滞](#1-%E6%9C%89%E6%97%B6%E4%BC%9A%E6%8A%BD%E9%A3%8E%E4%BC%9A%E5%8D%A1%E4%BD%8F%E5%81%9C%E6%BB%9E) 34 | - [2. 没翻译成功的有 数量/总数](#2-%E6%B2%A1%E7%BF%BB%E8%AF%91%E6%88%90%E5%8A%9F%E7%9A%84%E6%9C%89-%E6%95%B0%E9%87%8F%E6%80%BB%E6%95%B0) 35 | - [Tips](#tips) 36 | - [欢迎 👏 ISSUE 和 PULL](#%E6%AC%A2%E8%BF%8E--issue-%E5%92%8C-pull) 37 | - [特性](#%E7%89%B9%E6%80%A7) 38 | - [已分隔的代码](#%E5%B7%B2%E5%88%86%E9%9A%94%E7%9A%84%E4%BB%A3%E7%A0%81) 39 | 40 | 41 | 42 | ## 这个项目是 为了 所有-的-markdown-编写-文件 📃 翻译 的 `工具` 43 | 44 | ```js 45 | npm install -g translate-mds 46 | ``` 47 | 48 | ```js 49 | // all folder· 50 | translateMds md/ 51 | 52 | //or single file 53 | 54 | translateMds test.md 55 | ``` 56 | 57 | ## Demo 58 | 59 | ![demo](./imgs/demo.gif) 60 | 61 | ## 命令行选项 62 | 63 | ```bash 64 | translate [folder/single] md file language to you want 65 | 66 | Usage 67 | $ translateMds [folder/file name] [options] 68 | 69 | Example 70 | $ translateMds md/ 71 | 72 | [options] 73 | -a API : default < baidu > {google|baidu|youdao} 74 | -f from : default < auto 检验 > 75 | -t to : default < zh > 76 | -N num : default < 1 > {并发 数} 77 | -R rewrite : default < false > {yes/no 重新写入翻译} 78 | 79 | 🌟[high user options]❤️ 80 | 81 | -D debug 82 | -C cache : default: false 是否存储结果 83 | -G google.com : default < false > { cn => Google.com 的 api } 84 | -F force : default < false > { 当, 翻译的结果达不到 100%, 强行写入翻译文件 } 85 | -M match : default [ ". ", "! "//...] {match this str, merge translate result } 86 | -S skips : default ["... ", "etc. ", "i.e. "] {match this str will, skip merge translate result} 87 | -T types : default ["html", "code"] {过滤 AST 类型, 不翻译} 88 | --timewait : default: 80 { 每次请求的等待 80ms 时间} 89 | --values [path] : default: false {取出原文中需要翻译的文本,放入path文件} [single file]) 90 | --translate [path] : default: false {使用此path文件替代请求网络翻译, 可搭配--values使用} [single file] 91 | --text-glob [pattern] : default: false {文本匹配glob模式, 才能被翻译} 92 | --no-disk : default: false {do not use cached Result} 93 | --cache-name [filename]: : default: "translateMds" 存储的文件名 94 | --glob [pattern] : default: false {文件匹配glob模式, 才能被翻译} 95 | --ignore [relative file/folder] : default: false {忽略 文件/文件夹 字符串匹配, 可用`,`分隔多路径 } 96 | ``` 97 | 98 | --- 99 | 100 | ## My-translate-list 101 | 102 | [项目测试翻译列表](https://github.com/chinanf-boy/translate-mds-test-list) or 103 | [更多中文 🇨🇳 翻译列表](https://github.com/chinanf-boy/chinese-translate-list) 104 | 105 | ## 常见问题 106 | 107 | ### 1. 有时会抽风会卡住,停滞 108 | 109 | ```js 110 | If slow , may be you should try again or use -D 111 | ``` 112 | 113 | 问题来自 API, 你只要再运行. 114 | 115 | ### 2. 没翻译成功的有 数量/总数 116 | 117 | > 数量是 没有翻译成功/总数是 单个文件翻译总数 118 | 119 | 出现这样的问题, 一般是来自 不常见符号/或句子过长 导致的 字符移位. 120 | 121 | 这个时候, 你可以使用 `-D` 调试 / `-F` 强制写入文件 / 调整不常见的字符 122 | 123 | [具体可看](https://github.com/chinanf-boy/translate-mds/issues/22) 124 | 125 | ## Tips 126 | 127 | 1. 不同的文件格式, 使用[pandoc 转换看看](https://github.com/jgm/pandoc) 128 | 2. 不要`-f **`指定语言,`translation.js`会自动检测 129 | 130 | - `--timewait [number]` 可以拉长每次请求翻译的时间, 减少被禁 ip 131 | - `--values [file-path]` (单个文件使用) 获得将要翻译的原本输出文件 132 | - `--translate [file-path]` (单个文件使用) 取代请求 api, 改为使用此文件的翻译内容 133 | 134 | ### 欢迎 👏 ISSUE 和 PULL 135 | 136 | ## 特性 137 | 138 | - [x] 提高 http 之类的 md 格式准确率 139 | - [x] 自动换 翻译源 140 | - [x] 启用 md AST 141 | 142 | ## 已分隔的代码 143 | 144 | - [files-list](https://github.com/chinanf-boy/files-list) 145 | - [what-time](https://github.com/chinanf-boy/what-time) 146 | - [zh-to-en-symbol](https://github.com/chinanf-boy/zh-to-en-symbol) 147 | 148 | --- 149 | 150 | 使用 [`remark`](https://github.com/wooorm/remark) 提高精准度 151 | 152 | 使用 [`translation.js`](https://github.com/Selection-Translator/translation.js) 完成 与翻译网站的交互 153 | 154 | 还有个 [异步 Promise 递归的 例子](https://github.com/chinanf-boy/translate-mds/blob/master/src/setObjectKey.js#L78) 155 | -------------------------------------------------------------------------------- /README.en.md: -------------------------------------------------------------------------------- 1 | # translate .md to \*.md[![explain](http://llever.com/explain.svg)](https://github.com/chinanf-boy/explain-translateMds) [![install size](https://packagephobia.now.sh/badge?p=translate-mds)](https://packagephobia.now.sh/result?p=translate-mds) 2 | 3 | like 4 | 5 | ```bash 6 | .md to .「all-language」.md 7 | ``` 8 | 9 | [english](./README.en.md) 10 | 11 | --- 12 | 13 | [![Build Status](https://travis-ci.org/chinanf-boy/translate-mds.svg?branch=master)](https://travis-ci.org/chinanf-boy/translate-mds) 14 | [![codecov](https://codecov.io/gh/chinanf-boy/translate-mds/branch/master/graph/badge.svg)](https://codecov.io/gh/chinanf-boy/translate-mds) 15 | [![GitHub license](https://img.shields.io/github/license/chinanf-boy/translate-mds.svg)](https://github.com/chinanf-boy/translate-mds/blob/master/License) 16 | ![npm](https://img.shields.io/npm/v/translate-mds.svg) 17 | ![GitHub release](https://img.shields.io/github/tag/chinanf-boy/translate-mds.svg) 18 | 19 | ## life 20 | 21 | [help me live , live need money 💰](https://github.com/chinanf-boy/live-need-money) 22 | 23 | --- 24 | 25 | 26 | 27 | 28 | - [This project is for all-of-markdown-writing-files translation`工具`](#this-project-is-for-all-of-markdown-writing-files-translation%E5%B7%A5%E5%85%B7) 29 | - [Demo](#demo) 30 | - [Command line options](#command-line-options) 31 | - [My-translate-list](#my-translate-list) 32 | - [common problem](#common-problem) 33 | - [1. Sometimes the wind will get stuck and stagnate.](#1-sometimes-the-wind-will-get-stuck-and-stagnate) 34 | - [2. There are a number of totals that have not been translated successfully](#2-there-are-a-number-of-totals-that-have-not-been-translated-successfully) 35 | - [Tips](#tips) 36 | - [Welcome 👏 ISSUE and PULL](#welcome--issue-and-pull) 37 | - [characteristic](#characteristic) 38 | - [Split Code](#split-code) 39 | 40 | 41 | 42 | ## This project is for all-of-markdown-writing-files translation`工具` 43 | 44 | ```js 45 | npm install -g translate-mds 46 | ``` 47 | 48 | ```js 49 | // all folder· 50 | translateMds md/ 51 | 52 | //or single file 53 | 54 | translateMds test.md 55 | ``` 56 | 57 | ## Demo 58 | 59 | ![demo](./imgs/demo.gif) 60 | 61 | ## Command line options 62 | 63 | ```bash 64 | translate [folder/single] md file language to you want 65 | 66 | Usage 67 | $ translateMds [folder/file name] [options] 68 | 69 | Example 70 | $ translateMds md/ 71 | 72 | [options] 73 | -a API : default < baidu > {google|baidu|youdao} 74 | -f from : default < auto detect > 75 | -t to : default < zh > 76 | -N num : default < 1 > {async number} 77 | -R rewrite : default < false > {yes/no rewrite translate file} 78 | 79 | 🌟[high user options]❤️ 80 | 81 | -D debug 82 | -C cache : default: false cache in disk 83 | -G google.com : default: false { cn => com with Google api } 84 | -F force : default: false { If, translate result is no 100%, force wirte md file } 85 | -M match : default [ ". ", "! "//...] {match this str, merge translate result } 86 | -S skips : default ["... ", "etc. ", "i.e. "] {match this str will, skip merge translate result } 87 | -T types : default ["html", "code"] {pass the md AST type} 88 | --timewait : default < 80 > {each fetch api wait time} 89 | --values [path] : default: false {write the original of wait for translate file} [single file] 90 | --translate [path] : default: false {use this file translate} [single file] 91 | --text-glob [pattern] : default: false {text must be match, then be transalte} 92 | --no-disk : default: false {do not use cached Result} 93 | --cache-name [filename] : default: "translateMds" named the cache file 94 | --glob [pattern] : default: false {file must be match, then be transalte} 95 | --ignore [relative file/folder] : default: false {ignore files/folders string, split with `,` } 96 | ``` 97 | 98 | ## My-translate-list 99 | 100 | [Project test translation list](https://github.com/chinanf-boy/translate-mds-test-list)or[More Chinese 🇨🇳 translation list](https://github.com/chinanf-boy/chinese-translate-list) 101 | 102 | ## common problem 103 | 104 | ### 1. Sometimes the wind will get stuck and stagnate. 105 | 106 | ```js 107 | If slow , may be you should try again or use -D 108 | ``` 109 | 110 | The problem comes from the API, you just have to run it again. 111 | 112 | ### 2. There are a number of totals that have not been translated successfully 113 | 114 | > Quantity is no translation success / total is the total number of single file translations 115 | 116 | This problem occurs, usually from the shift of characters caused by unusual symbols or sentences that are too long. 117 | 118 | At this time, you can use`-D`Debug /`-F`Force write to file / Adjust unusual characters 119 | 120 | [Specific can be seen](https://github.com/chinanf-boy/translate-mds/issues/22) 121 | 122 | ## Tips 123 | 124 | 1. Diff file type, may try [pandoc converter](https://github.com/jgm/pandoc) 125 | 2. May use cli without `-f **`,cause `translation.js` auto detect language 126 | 127 | - `--timewait [number]` can lengthen the time of each request translation, reduce the banned ip 128 | - `--values [file-path]` (single file usage) to get the original output file to be translated 129 | - `--translate [file-path]` (single file usage) replaces the request api and uses the translated content of this file instead 130 | 131 | ### Welcome 👏 ISSUE and PULL 132 | 133 | ## characteristic 134 | 135 | - [x] Improve the accuracy of md format such as http 136 | 137 | - [x] Automatic translation 138 | 139 | - [x] Enable md AST 140 | 141 | ## Split Code 142 | 143 | - [files-list](https://github.com/chinanf-boy/files-list) 144 | - [what-time](https://github.com/chinanf-boy/what-time) 145 | - [zh-to-en-symbol](https://github.com/chinanf-boy/zh-to-en-symbol) 146 | 147 | --- 148 | 149 | Use[`remark`](https://github.com/wooorm/remark)Improve accuracy 150 | 151 | Use[`translation.js`](https://github.com/Selection-Translator/translation.js)Complete interaction with the translation website 152 | 153 | There is another[Asynchronous Promise recursive example](https://github.com/chinanf-boy/translate-mds/blob/master/src/setObjectKey.js#L78) 154 | -------------------------------------------------------------------------------- /cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | (async function () { 3 | "use script"; 4 | process.on("uncaughtException", (err) => { 5 | console.error("got an error: %s", err); 6 | process.exitCode = 1; 7 | }); 8 | 9 | const updateNotifier = require("update-notifier"); 10 | const whatTime = require("what-time"); 11 | const minimatch = require("minimatch"); 12 | const async = require("async"); 13 | const fs = require("fs"); 14 | const path = require("path"); 15 | const listMd = require("./src/util/readmd.js"); 16 | const meow = require("meow"); 17 | 18 | const mergeConfig = require("./src/config/mergeConfig.js"); 19 | 20 | const { 21 | g, 22 | y, 23 | yow, 24 | m, 25 | b, 26 | r, 27 | relaPath, 28 | insert_flg, 29 | } = require("./src/util/util.js"); 30 | 31 | // Cli cmd 32 | const cli = meow(` 33 | Usage 34 | $ translateMds [folder/file name] [options] 35 | 36 | Example 37 | $ translateMds md/ 38 | $ translateMds -T 'inlineCode,linkReference,link,heading' readme.md 39 | 40 | ${b("[options]")} 41 | ${g("-a API")} : default < baidu > ${y("{google|baidu|youdao}")} 42 | ${g("-f from ")} : default < auto detect > 43 | ${g("-t to ")} : default < zh > 44 | ${g("-N num ")} : default < 1 > ${y("{async number}")} 45 | ${g("-R rewrite")} : default < false > ${y( 46 | "{yes/no rewrite translate file}" 47 | )} 48 | 49 | 🌟${m("[high user options]")}❤️ 50 | 51 | ${g("-D debug")} 52 | ${g("-C cache")} : default: false ${y("cache in disk")} 53 | ${g("-G google.com")} : default: false ${y( 54 | "{ cn => com with Google api }" 55 | )} 56 | ${g("-F force")} : default: false ${y( 57 | "{ If, translate result is no 100%, force wirte md file }" 58 | )} 59 | ${g("-M match")} : default [ ". ", "! "//...] ${y( 60 | "{match this str, merge translate result }" 61 | )} 62 | ${g("-S skips")} : default ["... ", "etc. ", "i.e. "] ${y( 63 | "{match this str will, skip merge translate result }" 64 | )} 65 | ${g("-T types")} : default ["html", "code"] ${y( 66 | "{pass the md AST type}" 67 | )} 68 | ${g("--timewait ")} : default < 80 > ${y( 69 | "{each fetch api wait time}" 70 | )} 71 | ${g("--values [path]")} : default: false ${y( 72 | "{write the original of wait for translate file}" 73 | )} ${r("[single file]")} 74 | ${g("--translate [path]")} : default: false ${y( 75 | "{use this file translate}" 76 | )} ${r("[single file]")} 77 | ${g("--text-glob [pattern]")} : default: false ${y( 78 | "{text must be match, then be transalte}" 79 | )} 80 | ${g("--no-disk")} : default: false ${y( 81 | "{do not use cached Result}" 82 | )} 83 | ${g("--cache-name [filename]")}: default: "translateMds" ${y( 84 | "named the cache file" 85 | )} 86 | ${g("--glob [pattern]")} : default: false ${y( 87 | "{file must be match, then be transalte}" 88 | )} 89 | ${g("--ignore [relative file/folder]")} : default: false ${y( 90 | "{ignore files/folders string, split with `,` }" 91 | )} 92 | 93 | `); 94 | 95 | updateNotifier({ pkg: cli.pkg }).notify(); 96 | 97 | // Fix write file Path is absoulte 98 | const dir = cli.input[0]; 99 | if (!dir) { 100 | console.error(g("--> v" + cli.pkg.version), cli.help); 101 | process.exit(1); 102 | } 103 | 104 | // Merge config 105 | const { 106 | debug, 107 | tranFr, 108 | tranTo, 109 | api, 110 | rewrite, 111 | asyncNum, 112 | Force, 113 | ignores, 114 | glob, 115 | Cache, 116 | } = mergeConfig(cli); 117 | 118 | const translateMds = require("./src/translateMds.js"); 119 | 120 | const { 121 | loggerStart, 122 | loggerText, 123 | loggerStop, 124 | oneOra, 125 | } = require("./src/config/loggerConfig.js"); // Winston config 126 | 127 | // after workOptions ready 128 | const { writeDataToFile } = require("./src/util/writeDataToFile.js"); 129 | 130 | console.log(b(`> ${yow(`Cache:${Cache}`)} Starting 翻译`) + r(dir)); 131 | 132 | // Get floder markdown files Array 133 | const getList = await listMd(path.resolve(process.cwd(), dir), { 134 | deep: "all", 135 | }); 136 | 137 | console.log(b(`总文件数 ${getList.length}, 有些文件会跳过`)); 138 | 139 | let Done = 0; 140 | const noDone = []; 141 | let showAsyncnum = 0; 142 | 143 | loggerStart("translate running ... >> "); 144 | async.mapLimit(getList, asyncNum, runTranslate, (err, IsTranslateS) => { 145 | loggerStop(); 146 | if (noDone.length > 0) { 147 | process.exitCode = 1; 148 | } 149 | if (err) { 150 | throw err; 151 | } 152 | 153 | Done++; 154 | if (IsTranslateS.every((x) => Boolean(x))) { 155 | oneOra("All Done"); 156 | } else { 157 | if (debug !== "debug") { 158 | oneOra( 159 | `Some No Done , ${yow("use")} cli-option${r(" { -D } ")} find the Err` 160 | ); 161 | } 162 | if (!Force) { 163 | oneOra( 164 | `Or ${yow("use")} cli-option${r( 165 | " { -F } " 166 | )} Force put the translate Result` 167 | ); 168 | } 169 | if (debug === "debug" || Force) { 170 | oneOra( 171 | `[${g("DEBUG")}:${debug === "debug"}|${g("Force")}:${Force}] mode` 172 | ); 173 | } 174 | } 175 | oneOra(`time:${whatTime(process.uptime())}`); 176 | }); 177 | 178 | /** 179 | * @description async Translate filename value , Return true or false 180 | * @param {String} value 181 | * @returns {Boolean} 182 | */ 183 | 184 | async function runTranslate(value) { 185 | const rePath = relaPath(value); 186 | loggerText(`++++ <😊 > ${rePath}`); 187 | 188 | let State = true; 189 | Done++; 190 | 191 | const localDone = Done; 192 | 193 | // Filter same file 194 | if (value.endsWith(`.${tranTo}.md`) || !value.endsWith(".md")) { 195 | loggerText(b(`- 翻译的 - 或者 不是 md 文件的 ${g(rePath)}`)); 196 | return State; 197 | } 198 | if (value.match(/\.[a-zA-Z]{2}\.md+/)) { 199 | // TOGO country short name 200 | loggerText(b(`- 有后缀为 *.国家简写.md ${g(rePath)}`)); 201 | return State; 202 | } 203 | if (!rewrite && fs.existsSync(insert_flg(value, `.${tranTo}`, 3))) { 204 | loggerText(b(`已翻译, 不覆盖 ${g(rePath)}`)); 205 | return State; 206 | } 207 | if (glob && glob.some((g) => !minimatch(value, g, { matchBase: true }))) { 208 | loggerText(b(`glob, no match ${g(rePath)}`)); 209 | return State; 210 | } 211 | if ( 212 | ignores && 213 | ignores.some((ignore) => value.includes(path.resolve(ignore))) 214 | ) { 215 | loggerText(b(`ignore, ${g(rePath)}`)); 216 | return State; 217 | } 218 | 219 | loggerText(`1. do 第${localDone}文件 ${rePath}`); 220 | 221 | // Open async num 222 | showAsyncnum++; 223 | const startTime = new Date().getTime(); 224 | 225 | const _translateMds = await translateMds( 226 | [value, api, tranFr, tranTo], 227 | debug, 228 | true 229 | ); 230 | 231 | // Succeed / force wirte data 232 | if (_translateMds.every((x) => !x.error && x.text) || Force) { 233 | // Translate no ok 234 | const _tranData = _translateMds.map((x) => x.text); // Single file translate data 235 | 236 | await writeDataToFile(_tranData, value).then((text) => loggerText(text)); 237 | } 238 | 239 | let Err; 240 | for (const _t of _translateMds) { 241 | if (_t.error) { 242 | Err = _t.error; 243 | break; 244 | } 245 | } 246 | 247 | const endtime = new Date().getTime() - startTime; 248 | const humanTime = whatTime(endtime / 1000); 249 | 250 | if (State && !Err) { 251 | oneOra( 252 | `已搞定 第 ${localDone} 文件 - 并发${b(showAsyncnum)} -- ${b( 253 | humanTime 254 | )} - ${rePath}` 255 | ); 256 | } else { 257 | State = false; // Translate no ok 258 | if (!State) { 259 | // Write data no ok | translate no ok 260 | noDone.push(value); // If process exit code 261 | oneOra( 262 | `没完成 第 ${localDone} 文件 - 并发${b(showAsyncnum)} -- ${b( 263 | humanTime 264 | )} - ${rePath} \n ${Err}`, 265 | "fail" 266 | ); 267 | } 268 | } 269 | 270 | showAsyncnum--; 271 | 272 | return State; 273 | } 274 | 275 | process.on("exit", (_) => { 276 | loggerStop(); 277 | }); 278 | })(); 279 | -------------------------------------------------------------------------------- /src/setObjectKey.js: -------------------------------------------------------------------------------- 1 | const tjs = require("translation.js-fix"); 2 | 3 | // log 4 | const { 5 | logger, 6 | loggerStart, 7 | loggerText, 8 | oneOra, 9 | } = require("./config/loggerConfig.js"); 10 | 11 | // get config.json 12 | const { getOptions } = require("./config/work-options.js"); 13 | const configs = getOptions(); 14 | 15 | let tranF = configs["from"], 16 | tranT = configs["to"], 17 | COM = configs["com"], 18 | Force = configs["force"]; 19 | (timeWait = configs["timewait"]), 20 | (getValuesFile = configs["getvalues"]), 21 | (zhSymbal = configs["zh"]), 22 | (gotTranslateFile = configs["translate"]), 23 | (apis = configs["apis"]); 24 | 25 | // Cache right result 26 | let cache = configs["cache"]; 27 | let cacheName = configs["cacheName"]; 28 | let diskState = configs["disk"]; 29 | 30 | const { setDisk, getDisk } = require("./util/diskCache")(cacheName); 31 | 32 | // Fix china symbal 33 | const fixZhtoEn = require("./Fix/fixZhtoEn.js"); 34 | // Fix result.length no equal 35 | const { translateLengthEquals } = require("./Fix/lengthEqual.js"); 36 | // Fix Too Big Array to Chunk 37 | const { fixFileTooBig, indexMergeArr } = require("./Fix/fixFileTooBig.js"); 38 | const { 39 | tc, 40 | time, 41 | g, 42 | y, 43 | yow, 44 | m, 45 | b, 46 | r, 47 | relaPath, 48 | newObject, 49 | asyncWrite, 50 | asyncRead, 51 | } = require("./util/util.js"); 52 | const debugMsg = require("./util/debugMsg.js"); 53 | 54 | const MAXstring = 1300; 55 | 56 | // 57 | // get translate result 58 | 59 | /** 60 | * @description 61 | * @param {String|String[]} value 62 | * @param {String} api 63 | * @returns {String[]} 64 | */ 65 | async function translateValue(value, api) { 66 | let thisTranString; 67 | if (value instanceof Array) { 68 | thisTranString = value.join("\n"); 69 | } else { 70 | thisTranString = value; 71 | } 72 | await time(timeWait); 73 | 74 | if (tranT === "zh") tranT = "zh-CN"; 75 | 76 | let tjsOpts = { 77 | text: thisTranString, 78 | to: tranT, 79 | com: COM, 80 | }; 81 | 82 | if (tranF) { 83 | tjsOpts["from"] = tranF; 84 | } 85 | 86 | return tjs[api] 87 | .translate(tjsOpts) 88 | .then((result) => { 89 | if (!result.result) { 90 | throw new Error("「结果为空」"); 91 | } 92 | 93 | if (value.length == result.result.length) { 94 | return result.result; 95 | } 96 | 97 | if (value.length > result.result.length) { 98 | return translateValue(value.slice(result.result.length), api) 99 | .then((youdao) => { 100 | // tjs translate youdao BUG and tjs baidu will return undefined 101 | if (youdao) { 102 | if (youdao instanceof Array) { 103 | youdao.forEach((x) => result.result.push(x)); 104 | } else { 105 | result.result.push(youdao); 106 | } 107 | } 108 | return result.result; 109 | }) 110 | .catch((x) => { 111 | if (api == "baidu") { 112 | result.result = result.result.concat( 113 | value.slice(result.result.length) 114 | ); 115 | } 116 | return result.result; 117 | }); 118 | } 119 | 120 | return result.result; 121 | }) 122 | .catch((err) => { 123 | throw err; 124 | }); 125 | } 126 | 127 | const { getTypeValue, setTypeValue } = require("./typeSetAndGet"); 128 | 129 | /** 130 | * @description translate AST Key == value, return new Object 131 | * @param {Object} obj - remark AST 132 | * @param {Object} Opts - options 133 | * @param {String} Opts.api - defuault api 134 | * @param {String} Opts.name - file name 135 | 136 | * @returns {Object} - newObject 137 | */ 138 | async function setObjectKey(obj, opts) { 139 | let allAPi = apis; 140 | let api = opts.api; 141 | 142 | let howManyValNoTran = 0; 143 | let errMsg = ""; 144 | 145 | let tranArray = []; 146 | let thisTranArray = []; 147 | let resultArray = []; 148 | 149 | let newObj = newObject(obj); 150 | let tips = `${r("If slow/stagnant , should try again")}`; 151 | // put obj values to tranArray 152 | let sum = getTypeValue(obj, tranArray); 153 | if (!sum || !tranArray.length) { 154 | loggerText("no value " + sum, { 155 | level: "error", 156 | }); 157 | return "no value"; 158 | } 159 | 160 | if (tranArray.length) { 161 | // remove all \n 162 | tranArray = tranArray.map((x) => { 163 | if (x.indexOf("\n") >= 0) { 164 | return x.replace(/[\n]/g, " "); 165 | } 166 | return x; 167 | }); 168 | thisTranArray = tranArray; 169 | tranArray = []; 170 | // --values {cli options} 171 | if (getValuesFile) { 172 | await asyncWrite(getValuesFile, thisTranArray).then(function (ok) { 173 | loggerText(`${getValuesFile} saved`); 174 | }); 175 | 176 | return `you want ${g(relaPath(getValuesFile))} values save, so ${r( 177 | "skip" 178 | )} translate`; 179 | } 180 | } 181 | 182 | if (gotTranslateFile) { 183 | // custom translate file with single file 184 | let tContent = await asyncRead(gotTranslateFile); 185 | let relaP = relaPath(gotTranslateFile); 186 | if (tContent.length === thisTranArray.length) { 187 | oneOra(`you choose ${y(relaP)} be The translation`); 188 | resultArray = tContent; 189 | } else { 190 | throw new Error( 191 | `${g(relaP)} value length ${r("no equal")}\n translate-content:${y( 192 | tContent.length 193 | )}\n wait-translate:${y(thisTranArray.length)}` 194 | ); 195 | } 196 | } else { 197 | // Fix file Too Big 198 | let chunkTranArray = fixFileTooBig(thisTranArray); 199 | 200 | for (let third in chunkTranArray) { 201 | let thisChunkTran = chunkTranArray[third]; 202 | let thisInfo = ""; 203 | let isWork = true; 204 | // auto change translate source 205 | allAPi = allAPi.filter((x) => x != api); 206 | allAPi.push(api); 207 | let thisResult = []; 208 | 209 | // get cache disk with chunk result 210 | let cacheRes = getDisk(cacheName, { source: thisChunkTran.join("\n") }); 211 | if (cacheRes && cacheRes.result && diskState) { 212 | thisResult = cacheRes.result; 213 | isWork = false; 214 | thisInfo = y(`result: come from Cache disk` + diskState); 215 | } 216 | 217 | if (isWork) 218 | for (let i in allAPi) { 219 | // Auto next api 220 | 221 | loggerText( 222 | `2. ${yow(relaPath(opts.name))} use ${g(api)} ${ 223 | resultArray.length 224 | }/${thisTranArray.length} - ${tips}` 225 | ); 226 | 227 | try { 228 | if (thisChunkTran.join("").length > MAXstring) { 229 | // string > 300 230 | 231 | let thisChunkTranL_2 = Math.ceil(thisChunkTran.length / 2); 232 | 233 | let left = indexMergeArr(thisChunkTran, 0, thisChunkTranL_2); 234 | let right = indexMergeArr( 235 | thisChunkTran, 236 | thisChunkTranL_2, 237 | thisChunkTranL_2 238 | ); 239 | 240 | let t0 = await translateValue(left, api); 241 | let t1 = await translateValue(right, api); 242 | 243 | thisResult = t0.concat(t1); 244 | } else { 245 | thisResult = await translateValue(thisChunkTran, api); 246 | } // get Result Arr 247 | } catch (error) { 248 | if (!error.code) { 249 | loggerText(`${error.message} tjs-error, api:${y(api)}`, { 250 | level: "error", 251 | color: "red", 252 | }); 253 | } else { 254 | loggerText(`${error.code} ,api:${y(api)}`, { 255 | level: "error", 256 | color: "red", 257 | }); 258 | } 259 | thisResult = []; 260 | } 261 | 262 | // debug 263 | debugMsg(1, thisChunkTran, thisResult); 264 | 265 | // result-1 return translate value, break for allAPi 266 | if ( 267 | thisResult.length > 0 && 268 | thisResult.length >= thisChunkTran.length 269 | ) { 270 | let markChunkTran = [].concat(thisChunkTran); // mark some emoji, display the split 271 | if (thisChunkTran.length < thisResult.length) { 272 | // Fix use Fix/lengthEqual.js in every Chunk 273 | markChunkTran = translateLengthEquals(thisChunkTran, thisResult); // Fix 274 | } 275 | 276 | if (markChunkTran.length != thisResult.length) { 277 | // debug only unequal 278 | 279 | debugMsg(2, markChunkTran, thisResult); 280 | } 281 | 282 | if (thisChunkTran.length == thisResult.length) { 283 | // Fix Upper/Lower case 284 | for (let i in thisChunkTran) { 285 | if ( 286 | thisChunkTran[i].trim().toLowerCase() == 287 | thisResult[i].trim().toLowerCase() 288 | ) { 289 | thisResult[i] = thisChunkTran[i]; 290 | } 291 | } 292 | break; 293 | } 294 | } 295 | 296 | api = allAPi[i]; 297 | // result-2 return source value 298 | if (+i + 1 == allAPi.length) { 299 | // ending is no result 300 | 301 | // count how many string no translate 302 | howManyValNoTran += thisChunkTran.length; 303 | isWork = false; 304 | thisResult = thisChunkTran; // Add source tran 305 | errMsg = `PS: can not get translation from API`; 306 | } 307 | } 308 | 309 | resultArray = resultArray.concat(thisResult); // Add result 310 | 311 | loggerText( 312 | `3. translate loading - ${resultArray.length}/${thisTranArray.length} < ${thisInfo}` 313 | ); 314 | 315 | if (errMsg && !Force) { 316 | break; 317 | } else if (!errMsg && cache && !thisInfo) { 318 | // cache with cache-name 319 | let cacheStruct = { 320 | time: new Date().getTime(), 321 | api: api, 322 | f: tranF, 323 | t: tranT, 324 | source: thisChunkTran.join("\n"), 325 | result: thisResult, 326 | }; 327 | 328 | setDisk(cacheName, { source: cacheStruct.source }, cacheStruct); 329 | loggerText(`3.1. ${g("cached")} the translate result`); 330 | } 331 | } 332 | } 333 | 334 | if (!errMsg || Force) { 335 | // default: zh symbal ,。! 336 | !zhSymbal && (resultArray = fixZhtoEn(resultArray)); 337 | 338 | setTypeValue(newObj, resultArray); 339 | } 340 | 341 | if (howManyValNoTran > 0) { 342 | newObj.Error = `translated number: ${ 343 | resultArray.length - howManyValNoTran 344 | }/${thisTranArray.length} ${errMsg}`; 345 | } 346 | 347 | return newObj; 348 | } 349 | 350 | module.exports = { 351 | setObjectKey, 352 | translateValue, 353 | }; 354 | -------------------------------------------------------------------------------- /License: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yobrave] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [Unreleased](https://github.com/chinanf-boy/translate-mds/tree/HEAD) 4 | 5 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.2.17...HEAD) 6 | 7 | **Closed issues:** 8 | 9 | - Add: --text-glob [\#23](https://github.com/chinanf-boy/translate-mds/issues/23) 10 | 11 | ## [v3.2.17](https://github.com/chinanf-boy/translate-mds/tree/v3.2.17) (2018-10-16) 12 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.2.16...v3.2.17) 13 | 14 | ## [v3.2.16](https://github.com/chinanf-boy/translate-mds/tree/v3.2.16) (2018-10-13) 15 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.2.15...v3.2.16) 16 | 17 | ## [v3.2.15](https://github.com/chinanf-boy/translate-mds/tree/v3.2.15) (2018-09-19) 18 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.2.14...v3.2.15) 19 | 20 | ## [v3.2.14](https://github.com/chinanf-boy/translate-mds/tree/v3.2.14) (2018-09-17) 21 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.2.13...v3.2.14) 22 | 23 | ## [v3.2.13](https://github.com/chinanf-boy/translate-mds/tree/v3.2.13) (2018-09-16) 24 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.2.12...v3.2.13) 25 | 26 | ## [v3.2.12](https://github.com/chinanf-boy/translate-mds/tree/v3.2.12) (2018-09-16) 27 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.2.11...v3.2.12) 28 | 29 | ## [v3.2.11](https://github.com/chinanf-boy/translate-mds/tree/v3.2.11) (2018-09-15) 30 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.2.10...v3.2.11) 31 | 32 | ## [v3.2.10](https://github.com/chinanf-boy/translate-mds/tree/v3.2.10) (2018-09-13) 33 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.2.9...v3.2.10) 34 | 35 | ## [v3.2.9](https://github.com/chinanf-boy/translate-mds/tree/v3.2.9) (2018-09-10) 36 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.2.8...v3.2.9) 37 | 38 | ## [v3.2.8](https://github.com/chinanf-boy/translate-mds/tree/v3.2.8) (2018-09-01) 39 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.2.7...v3.2.8) 40 | 41 | ## [v3.2.7](https://github.com/chinanf-boy/translate-mds/tree/v3.2.7) (2018-09-01) 42 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.2.6...v3.2.7) 43 | 44 | ## [v3.2.6](https://github.com/chinanf-boy/translate-mds/tree/v3.2.6) (2018-08-26) 45 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.2.5...v3.2.6) 46 | 47 | ## [v3.2.5](https://github.com/chinanf-boy/translate-mds/tree/v3.2.5) (2018-08-26) 48 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.2.4...v3.2.5) 49 | 50 | ## [v3.2.4](https://github.com/chinanf-boy/translate-mds/tree/v3.2.4) (2018-08-26) 51 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.2.3...v3.2.4) 52 | 53 | ## [v3.2.3](https://github.com/chinanf-boy/translate-mds/tree/v3.2.3) (2018-08-26) 54 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.2.2...v3.2.3) 55 | 56 | ## [v3.2.2](https://github.com/chinanf-boy/translate-mds/tree/v3.2.2) (2018-08-26) 57 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.2.1...v3.2.2) 58 | 59 | ## [v3.2.1](https://github.com/chinanf-boy/translate-mds/tree/v3.2.1) (2018-08-26) 60 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.2.0...v3.2.1) 61 | 62 | ## [v3.2.0](https://github.com/chinanf-boy/translate-mds/tree/v3.2.0) (2018-08-25) 63 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.1.6...v3.2.0) 64 | 65 | ## [v3.1.6](https://github.com/chinanf-boy/translate-mds/tree/v3.1.6) (2018-08-23) 66 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.1.5...v3.1.6) 67 | 68 | ## [v3.1.5](https://github.com/chinanf-boy/translate-mds/tree/v3.1.5) (2018-08-23) 69 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.1.4...v3.1.5) 70 | 71 | ## [v3.1.4](https://github.com/chinanf-boy/translate-mds/tree/v3.1.4) (2018-08-23) 72 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.1.3...v3.1.4) 73 | 74 | ## [v3.1.3](https://github.com/chinanf-boy/translate-mds/tree/v3.1.3) (2018-08-23) 75 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.1.2...v3.1.3) 76 | 77 | ## [v3.1.2](https://github.com/chinanf-boy/translate-mds/tree/v3.1.2) (2018-08-23) 78 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.1.1...v3.1.2) 79 | 80 | ## [v3.1.1](https://github.com/chinanf-boy/translate-mds/tree/v3.1.1) (2018-08-22) 81 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.1.0...v3.1.1) 82 | 83 | ## [v3.1.0](https://github.com/chinanf-boy/translate-mds/tree/v3.1.0) (2018-08-21) 84 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.0.23...v3.1.0) 85 | 86 | ## [v3.0.23](https://github.com/chinanf-boy/translate-mds/tree/v3.0.23) (2018-08-21) 87 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.0.22...v3.0.23) 88 | 89 | ## [v3.0.22](https://github.com/chinanf-boy/translate-mds/tree/v3.0.22) (2018-08-20) 90 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.0.21...v3.0.22) 91 | 92 | ## [v3.0.21](https://github.com/chinanf-boy/translate-mds/tree/v3.0.21) (2018-07-23) 93 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.0.20...v3.0.21) 94 | 95 | ## [v3.0.20](https://github.com/chinanf-boy/translate-mds/tree/v3.0.20) (2018-07-22) 96 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.0.19...v3.0.20) 97 | 98 | ## [v3.0.19](https://github.com/chinanf-boy/translate-mds/tree/v3.0.19) (2018-07-21) 99 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.0.18...v3.0.19) 100 | 101 | ## [v3.0.18](https://github.com/chinanf-boy/translate-mds/tree/v3.0.18) (2018-07-04) 102 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.0.17...v3.0.18) 103 | 104 | ## [v3.0.17](https://github.com/chinanf-boy/translate-mds/tree/v3.0.17) (2018-06-29) 105 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.0.16...v3.0.17) 106 | 107 | **Closed issues:** 108 | 109 | - 斜杠 错误❌ [\#21](https://github.com/chinanf-boy/translate-mds/issues/21) 110 | 111 | ## [v3.0.16](https://github.com/chinanf-boy/translate-mds/tree/v3.0.16) (2018-06-24) 112 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.0.15...v3.0.16) 113 | 114 | **Closed issues:** 115 | 116 | - 小心 transalteMds -M "- " ❌ [\#20](https://github.com/chinanf-boy/translate-mds/issues/20) 117 | 118 | ## [v3.0.15](https://github.com/chinanf-boy/translate-mds/tree/v3.0.15) (2018-06-11) 119 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.0.14...v3.0.15) 120 | 121 | ## [v3.0.14](https://github.com/chinanf-boy/translate-mds/tree/v3.0.14) (2018-06-11) 122 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.0.13...v3.0.14) 123 | 124 | ## [v3.0.13](https://github.com/chinanf-boy/translate-mds/tree/v3.0.13) (2018-06-11) 125 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.0.12...v3.0.13) 126 | 127 | ## [v3.0.12](https://github.com/chinanf-boy/translate-mds/tree/v3.0.12) (2018-06-11) 128 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.0.11...v3.0.12) 129 | 130 | ## [v3.0.11](https://github.com/chinanf-boy/translate-mds/tree/v3.0.11) (2018-05-26) 131 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.0.10...v3.0.11) 132 | 133 | ## [v3.0.10](https://github.com/chinanf-boy/translate-mds/tree/v3.0.10) (2018-05-24) 134 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.0.9...v3.0.10) 135 | 136 | ## [v3.0.9](https://github.com/chinanf-boy/translate-mds/tree/v3.0.9) (2018-05-24) 137 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.0.8...v3.0.9) 138 | 139 | **Closed issues:** 140 | 141 | - 大小写 [\#19](https://github.com/chinanf-boy/translate-mds/issues/19) 142 | 143 | ## [v3.0.8](https://github.com/chinanf-boy/translate-mds/tree/v3.0.8) (2018-05-24) 144 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.0.7...v3.0.8) 145 | 146 | ## [v3.0.7](https://github.com/chinanf-boy/translate-mds/tree/v3.0.7) (2018-05-20) 147 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.0.6...v3.0.7) 148 | 149 | ## [v3.0.6](https://github.com/chinanf-boy/translate-mds/tree/v3.0.6) (2018-05-06) 150 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.0.5...v3.0.6) 151 | 152 | ## [v3.0.5](https://github.com/chinanf-boy/translate-mds/tree/v3.0.5) (2018-05-01) 153 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.0.4...v3.0.5) 154 | 155 | **Closed issues:** 156 | 157 | - 当 travis Ci 与 npm 配合 [\#3](https://github.com/chinanf-boy/translate-mds/issues/3) 158 | 159 | ## [v3.0.4](https://github.com/chinanf-boy/translate-mds/tree/v3.0.4) (2018-04-07) 160 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.0.3...v3.0.4) 161 | 162 | ## [v3.0.3](https://github.com/chinanf-boy/translate-mds/tree/v3.0.3) (2018-04-03) 163 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.0.2...v3.0.3) 164 | 165 | ## [v3.0.2](https://github.com/chinanf-boy/translate-mds/tree/v3.0.2) (2018-03-27) 166 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.0.1...v3.0.2) 167 | 168 | ## [v3.0.1](https://github.com/chinanf-boy/translate-mds/tree/v3.0.1) (2018-03-26) 169 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v3.0.0...v3.0.1) 170 | 171 | ## [v3.0.0](https://github.com/chinanf-boy/translate-mds/tree/v3.0.0) (2018-03-26) 172 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v2.5.8...v3.0.0) 173 | 174 | **Fixed bugs:** 175 | 176 | - 英文句子中带有 句号 `.` --\> 导致翻译位置错位 [\#15](https://github.com/chinanf-boy/translate-mds/issues/15) 177 | - 文件过大-翻译失败 [\#14](https://github.com/chinanf-boy/translate-mds/issues/14) 178 | - 翻译前的中文符号 导致 翻译源 不对应 [\#13](https://github.com/chinanf-boy/translate-mds/issues/13) 179 | - ㄢ 出现 [\#11](https://github.com/chinanf-boy/translate-mds/issues/11) 180 | - markdown html 文本 没有过滤 [\#8](https://github.com/chinanf-boy/translate-mds/issues/8) 181 | 182 | **Closed issues:** 183 | 184 | - 本项目的 `api` 作者更新 [\#12](https://github.com/chinanf-boy/translate-mds/issues/12) 185 | - 卡住问题, 没有反应,出现在 几十个文件的时候 [\#10](https://github.com/chinanf-boy/translate-mds/issues/10) 186 | 187 | **Merged pull requests:** 188 | 189 | - Fix file Too Big [\#17](https://github.com/chinanf-boy/translate-mds/pull/17) ([chinanf-boy](https://github.com/chinanf-boy)) 190 | - Fix translate.length no equal [\#16](https://github.com/chinanf-boy/translate-mds/pull/16) ([chinanf-boy](https://github.com/chinanf-boy)) 191 | 192 | ## [v2.5.8](https://github.com/chinanf-boy/translate-mds/tree/v2.5.8) (2018-01-06) 193 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v2.5.7...v2.5.8) 194 | 195 | ## [v2.5.7](https://github.com/chinanf-boy/translate-mds/tree/v2.5.7) (2018-01-06) 196 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v2.5.6...v2.5.7) 197 | 198 | ## [v2.5.6](https://github.com/chinanf-boy/translate-mds/tree/v2.5.6) (2017-12-10) 199 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v2.5.5...v2.5.6) 200 | 201 | **Merged pull requests:** 202 | 203 | - fix while and html markdown [\#9](https://github.com/chinanf-boy/translate-mds/pull/9) ([chinanf-boy](https://github.com/chinanf-boy)) 204 | 205 | ## [v2.5.5](https://github.com/chinanf-boy/translate-mds/tree/v2.5.5) (2017-12-06) 206 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v2.5.4...v2.5.5) 207 | 208 | ## [v2.5.4](https://github.com/chinanf-boy/translate-mds/tree/v2.5.4) (2017-12-06) 209 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v2.5.3...v2.5.4) 210 | 211 | ## [v2.5.3](https://github.com/chinanf-boy/translate-mds/tree/v2.5.3) (2017-12-06) 212 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v2.5.2...v2.5.3) 213 | 214 | **Merged pull requests:** 215 | 216 | - Up from and to [\#7](https://github.com/chinanf-boy/translate-mds/pull/7) ([chinanf-boy](https://github.com/chinanf-boy)) 217 | - fix .zh.md .zh.ja.md [\#6](https://github.com/chinanf-boy/translate-mds/pull/6) ([chinanf-boy](https://github.com/chinanf-boy)) 218 | 219 | ## [v2.5.2](https://github.com/chinanf-boy/translate-mds/tree/v2.5.2) (2017-11-24) 220 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v2.5.1...v2.5.2) 221 | 222 | **Merged pull requests:** 223 | 224 | - Up from and to [\#4](https://github.com/chinanf-boy/translate-mds/pull/4) ([chinanf-boy](https://github.com/chinanf-boy)) 225 | 226 | ## [v2.5.1](https://github.com/chinanf-boy/translate-mds/tree/v2.5.1) (2017-11-24) 227 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v2.5.0...v2.5.1) 228 | 229 | ## [v2.5.0](https://github.com/chinanf-boy/translate-mds/tree/v2.5.0) (2017-11-22) 230 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v2.4.0...v2.5.0) 231 | 232 | **Closed issues:** 233 | 234 | - 翻译源 google.cn baidu youdao [\#2](https://github.com/chinanf-boy/translate-mds/issues/2) 235 | 236 | ## [v2.4.0](https://github.com/chinanf-boy/translate-mds/tree/v2.4.0) (2017-11-21) 237 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v2.3.0...v2.4.0) 238 | 239 | ## [v2.3.0](https://github.com/chinanf-boy/translate-mds/tree/v2.3.0) (2017-11-21) 240 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v2.2.0...v2.3.0) 241 | 242 | ## [v2.2.0](https://github.com/chinanf-boy/translate-mds/tree/v2.2.0) (2017-11-21) 243 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v2.1.0...v2.2.0) 244 | 245 | ## [v2.1.0](https://github.com/chinanf-boy/translate-mds/tree/v2.1.0) (2017-11-21) 246 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v2.0.2...v2.1.0) 247 | 248 | **Closed issues:** 249 | 250 | - 翻译出来的文本 [\#1](https://github.com/chinanf-boy/translate-mds/issues/1) 251 | 252 | ## [v2.0.2](https://github.com/chinanf-boy/translate-mds/tree/v2.0.2) (2017-11-20) 253 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v2.0.1...v2.0.2) 254 | 255 | ## [v2.0.1](https://github.com/chinanf-boy/translate-mds/tree/v2.0.1) (2017-11-20) 256 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v2.0.0...v2.0.1) 257 | 258 | ## [v2.0.0](https://github.com/chinanf-boy/translate-mds/tree/v2.0.0) (2017-11-20) 259 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v1.4.0...v2.0.0) 260 | 261 | ## [v1.4.0](https://github.com/chinanf-boy/translate-mds/tree/v1.4.0) (2017-11-18) 262 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v1.3.1...v1.4.0) 263 | 264 | ## [v1.3.1](https://github.com/chinanf-boy/translate-mds/tree/v1.3.1) (2017-11-18) 265 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v1.3.0...v1.3.1) 266 | 267 | ## [v1.3.0](https://github.com/chinanf-boy/translate-mds/tree/v1.3.0) (2017-11-18) 268 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v1.2.0...v1.3.0) 269 | 270 | ## [v1.2.0](https://github.com/chinanf-boy/translate-mds/tree/v1.2.0) (2017-11-17) 271 | [Full Changelog](https://github.com/chinanf-boy/translate-mds/compare/v1.1.0...v1.2.0) 272 | 273 | ## [v1.1.0](https://github.com/chinanf-boy/translate-mds/tree/v1.1.0) (2017-11-17) 274 | 275 | 276 | \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* --------------------------------------------------------------------------------