驼峰翻译助手 - 自动翻译为变量的大驼峰、小驼峰、短横线等命名格式(支持搜狗翻译、有道翻译、百度翻译)
// ==UserScript==
// @name 驼峰翻译助手 - 自动翻译为变量的大驼峰、小驼峰、短横线等命名格式(支持搜狗翻译、有道翻译、百度翻译)
// @namespace http://tampermonkey.net/
// @version 0.1
// @description 平常开发取变量名的时候,经常要到翻译网站翻译,翻译结果又要手动转大驼峰、小驼峰、短横线,于是自己开发了一套油猴脚本,直接自动翻译成程序员常用的命名格式。
// @author Kai
// @match https://www.tampermonkey.net/index.php?ext=dhdg
// @icon https://www.google.com/s2/favicons?sz=64&domain=tampermonkey.net
// @grant none
// @match *://fanyi.sogou.com/text*
// @match *://fanyi.youdao.com/*
// @match *://fanyi.baidu.com/*
// @require http://cdn.bootcss.com/jquery/2.2.4/jquery.min.js
// @require https://unpkg.com/pxmu@1.1.0/dist/web/pxmu.min.js
// ==/UserScript==
(function () {
'use strict';
//===========================声明各种格式的策略对象=========================================
//toCamelCase(‘it is word’) => ‘itIsWord’
function toLowerCamelCase(str) {
if (!str) {
return '';
}
try {
const s = str
.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
.map((x) => x.slice(0, 1).toUpperCase() + x.slice(1).toLowerCase())
.join('')
return s.slice(0, 1).toLowerCase() + s.slice(1)
} catch (e) {
return '解析异常'
}
}
//console.log(camelize("Concurrent hash maps")) =》ConcurrentHashMaps
function toPascalCase(str) {
if (!str) {
return '';
}
try {
//过滤字符串
return str.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
//将每个单词的第一个字符转换为大写
.map(a => a[0].toUpperCase() + a.substring(1))
//将所有字符串重新连接在一起
.join("")
} catch (e) {
return '解析异常'
}
}
//console.log(camelize("Concurrent hash maps")) =》concurrent-hash-maps
function toKebabCase(str) {
if (!str) {
return '';
}
try {
let strList = str.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
return strList.reduce((result, a, index) => {
//将每个单词转换为小写
let suffix = index === strList.length - 1 ? '' : "-"
result += a.toLowerCase() + suffix
return result
}, '')
} catch (e) {
return '解析异常'
}
}
//console.log(camelize("Concurrent hash maps")) =》concurrent_hash_maps
function toSnakeCase(str) {
if (!str) {
return '';
}
try {
let strList = str.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
return strList.reduce((result, a, index) => {
//将每个单词转换为小写
let suffix = index === strList.length - 1 ? '' : "_"
result += a.toLowerCase() + suffix
return result
}, '')
} catch (e) {
return '解析异常'
}
}
//console.log(camelize("Concurrent hash maps")) =》CONCURRENT_HASH_MAPS
function toScreamingSnakeCase(str) {
if (!str) {
return '';
}
try {
let strList = str.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
return strList.reduce((result, a, index) => {
//将每个单词转换为大写
let suffix = index === strList.length - 1 ? '' : "_"
result += a.toUpperCase() + suffix
return result
}, '')
} catch (e) {
return '解析异常'
}
}
var whichNameType = {
toLowerCamelCase: toLowerCamelCase,
toPascalCase: toPascalCase,
toKebabCase: toKebabCase,
toSnakeCase: toSnakeCase,
toScreamingSnakeCase: toScreamingSnakeCase
}
var currentWhichNameType = 'toLowerCamelCase'
var whichNameHtml = `
<div id="whichName"
style="z-index: 99999;width: 286px;background:#fff;font-size: 16px;color: rgba(0,0,0,.65);position: fixed;right: 0;top: 194px;border-radius: 4px;white-space:normal;border: 1px solid #e8e8e8;">
<div style="padding: 14px;color: #000;font-weight: 600;font-size: 16px;border-bottom: 1px solid #e8e8e8;">驼峰翻译助手
</div>
<div style="padding: 14px;">
<div style="font-weight: bold;margin-bottom: 10px;">
格式:
</div>
<div>
<label style="cursor: pointer">
<input style="width: 14px;margin-right: 5px;" type="radio" name="whichNameType" value="toLowerCamelCase"
checked/>小驼峰
</label>
<label style="cursor: pointer">
<input style="width: 14px;margin-right: 5px;" type="radio" name="whichNameType" value="toPascalCase"/>大驼峰
</label>
<label style="cursor: pointer">
<input style="width: 14px;margin-right: 5px;" type="radio" name="whichNameType" value="toKebabCase"/>短横线分割
</label>
<label style="cursor: pointer">
<input style="width: 14px;margin-right: 5px;" type="radio" name="whichNameType" value="toSnakeCase"/>下划线分割
</label>
<label style="cursor: pointer">
<input style="width: 14px;margin-right: 5px;" type="radio" name="whichNameType"
value="toScreamingSnakeCase"/>大写下划线分割
</label>
</div>
<div style="font-weight: bold;margin: 10px 0;display: flex;justify-content: space-between;">
<span>结果:</span>
<div id="which-name-copy" style="cursor: pointer;color: #fd6853">
一键复制
<svg t="1665638145142" class="icon" viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="4929" width="16" height="16">
<path d="M638.596211 191.936191q30.628116 0 54.62014 13.272183t41.347956 32.66999 26.544367 41.858425 9.188435 39.81655l0 576.829511q0 29.607178-11.740778 53.088734t-30.628116 39.81655-42.368893 25.52343-46.963111 9.188435l-503.322034 0q-19.397807 0-42.368893-11.230309t-42.879362-29.607178-33.180459-42.368893-13.272183-48.494516l0-568.662014q0-21.439681 10.209372-44.410768t26.544367-42.368893 37.774676-32.159521 44.921236-12.761715l515.57328 0zM578.360917 830.021934q26.544367 0 45.431705-18.376869t18.887338-44.921236-18.887338-45.431705-45.431705-18.887338l-382.851446 0q-26.544367 0-45.431705 18.887338t-18.887338 45.431705 18.887338 44.921236 45.431705 18.376869l382.851446 0zM578.360917 574.787637q26.544367 0 45.431705-18.376869t18.887338-44.921236-18.887338-45.431705-45.431705-18.887338l-382.851446 0q-26.544367 0-45.431705 18.887338t-18.887338 45.431705 18.887338 44.921236 45.431705 18.376869l382.851446 0zM759.0668 0q43.900299 0 80.654038 26.033898t63.808574 64.319043 42.368893 82.695912 15.314058 81.164506l0 542.117647q0 21.439681-12.761715 39.306082t-31.138584 30.628116-39.81655 20.418744-39.81655 7.657029l-4.083749 0 0-609.499501q-8.167498-70.444666-43.900299-108.219342t-94.947159-49.004985l-498.217348 0q1.020937-2.041874 1.020937-7.14656 0-20.418744 12.251246-41.858425t32.159521-38.795613 44.410768-28.586241 49.004985-11.230309l423.688933 0z"
p-id="4930" fill="#fd6853"></path>
</svg>
</div>
</div>
<p id="which-name-result" style="word-break: break-all;white-space:normal;word-wrap: break-word;"/>
</div>
</div>`
//添加操作区域
$("body").append(whichNameHtml)
//首先判断是搜狗翻译、有道云翻译还是百度翻译
//根据网站获取结果不同的inputDom
//=================================匹配url========================================
let opt = {
'sougou': {
urlExp: 'https://fanyi.sogou.com/text',
//结果变化的输入框dom
input: '#trans-result',
name: '搜狗'
},
'youdao': {
urlExp: 'https://fanyi.youdao.com/',
input: '#transTarget',
name: '有道'
},
'baidu': {
urlExp: 'https://fanyi.baidu.com/',
input: '.output-wrap',
name: '百度'
},
}
var inputDom = null
for (let key of Object.keys(opt)) {
let item = opt[key]
if (location.href.match(item.urlExp)) {
inputDom = $(item.input)
console.log('dom', item.input)
break
}
}
if (!inputDom) {
console.warn('驼峰翻译助手:识别输入框dom失败')
return
}
function updateValue() {
console.log('翻译事件监听...')
let result = whichNameType[currentWhichNameType](inputDom.text())
console.log('翻译结果:', result)
$("#which-name-result").text(result)
}
//第一次进来需要加载一次数据
updateValue()
//绑定事件:DOMNodeInserted、DOMSubtreeModified
inputDom.bind("DOMSubtreeModified", function (e) {
updateValue()
})
//绑定单选框切换事件
$("input[type=radio][name=whichNameType]").change(function () {
console.log('监听单选框', this.value)
currentWhichNameType = this.value
updateValue()
})
//复制事件
$("#which-name-copy").click(function () {
const input = document.createElement('textarea')
input.value = whichNameType[currentWhichNameType](inputDom.text())
document.body.appendChild(input)
input.select()
document.execCommand('Copy')
document.body.removeChild(input)
pxmu.toast({msg: '复制成功!', location: 'top'})
})
})();