提交 face1458 编写于 作者: B baiy 提交者: ninecents

i18n

上级 5927807b
......@@ -21,7 +21,6 @@
"cronstrue": "^1.122.0",
"crypto-js": "^3.3.0",
"file": "^0.2.2",
"http-build-query": "^0.7.0",
"ipinyinjs": "^1.0.0",
"is-url": "^1.2.4",
"jian_fan": "^1.0.3",
......@@ -29,6 +28,7 @@
"js-htmlencode": "^0.3.0",
"js-yaml": "^3.14.1",
"json-to-properties": "^1.1.3",
"json5": "^2.2.0",
"jsonlint": "^1.6.3",
"jsrsasign": "^10.4.1",
"jsrsasign-util": "^1.0.5",
......@@ -48,13 +48,14 @@
"properties-to-json": "^0.1.7",
"qrcode": "^1.4.4",
"qrcode-parser": "^1.2.0",
"query-string": "^6.13.7",
"query-string": "^6.14.1",
"serialize-php": "^1.1.2",
"sm-crypto": "^0.1.4",
"system": "^2.0.1",
"uuid": "^8.3.2",
"view-design": "^4.6.1",
"vue": "^2.6.14",
"vue-i18n": "^8.26.5",
"vue-router": "^3.5.3",
"x2js": "github:abdolence/x2js"
},
......@@ -92,6 +93,9 @@
},
"parserOptions": {
"parser": "babel-eslint"
},
"globals": {
"__": "writable"
}
},
"postcss": {
......
export const openUrl = (url) => {
// return chrome.tabs.create();
// return chrome.windows.create();
if (url.indexOf('chrome://') === 0){
return chrome.tabs.create({url:url});
if (url.indexOf('chrome://') === 0) {
return chrome.tabs.create({url: url});
}
return window.open(url);
}
\ No newline at end of file
}
export const getMessage = (messageName, values = {}, placeholders = [], options = {}) => {
let substitutions = []
placeholders.forEach((key) => {
substitutions.push((key in values) ? values[key] : "")
})
return chrome.i18n.getMessage(messageName, substitutions, options);
}
......@@ -14,53 +14,51 @@ const DEFAULT_COMMON_TOOL = [
]
const category = [
{'name': 'common', 'title': '常用'},
{'name': 'encryption', 'title': '加解密'},
{'name': 'conversion', 'title': '转换'},
{'name': 'serialize', 'title': '序列化'},
{'name': 'check', 'title': '校验'},
{'name': 'generate', 'title': '生成'},
{'name': 'other', 'title': '其他'},
{'name': 'common'},
{'name': 'encryption'},
{'name': 'conversion'},
{'name': 'serialize'},
{'name': 'check'},
{'name': 'generate'},
{'name': 'other'},
]
const tool = [
{
'name': 'hash',
'title': '哈希(hash)',
'cat': ['encryption']
},
{
'name': 'encrypt',
'title': '加密/解密',
'cat': ['encryption']
},
{'name': 'sign', 'title': '签名/验签', 'cat': ['encryption']},
{'name': 'base64', 'title': 'BASE64编码', 'cat': ['encryption']},
{'name': 'json', 'title': 'JSON工具', 'cat': ['conversion', 'serialize']},
{'name': 'url', 'title': 'URL编码', 'cat': ['conversion']},
{'name': 'timestamp', 'title': '时间戳', 'cat': ['conversion']},
{'name': 'qrCode', 'title': '二维码', 'cat': ['generate']},
{'name': 'pinyin', 'title': '汉字转拼音', 'cat': ['conversion']},
{'name': 'ip', 'title': 'IP地址查询', 'cat': ['other']},
{'name': 'code', 'title': '代码格式化', 'cat': ['other']},
{'name': 'unicode', 'title': 'Unicode', 'cat': ['conversion']},
{'name': 'decimalConvert', 'title': '进制转换', 'cat': ['conversion']},
{'name': 'regex', 'title': '正则表达式', 'cat': ['check']},
{'name': 'randomString', 'title': '随机字符生成', 'cat': ['generate']},
{'name': 'serializeConversion', 'title': '序列化转换', 'cat': ['conversion', 'serialize']},
{'name': 'diffs', 'title': '文本差异化对比', 'cat': ['check']},
{'name': 'crontab', 'title': 'crontab校验', 'cat': ['check']},
{'name': 'websocket', 'title': 'websocket调试', 'cat': ['other']},
{'name': 'unit', 'title': '单位换算', 'cat': ['other']},
{'name': 'time', 'title': '时间计算器', 'cat': ['other']},
{'name': 'uuid', 'title': 'UUID生成', 'cat': ['generate']},
{'name': 'jsonToObject', 'title': 'JSON转实体类', 'cat': ['conversion', 'serialize']},
{'name': 'ascii', 'title': 'ASCII转换', 'cat': ['conversion']},
{'name': 'variableConversion', 'title': '变量名转换', 'cat': ['conversion']},
{'name': 'jwt', 'title': 'JWT解码', 'cat': ['conversion']},
{'name': 'hexString', 'title': 'Hex/String转换', 'cat': ['conversion']},
{'name': 'text', 'title': '文本处理', 'cat': ['other']},
{'name': 'html', 'title': 'html编码', 'cat': ['conversion']},
{'name': 'sign', 'cat': ['encryption']},
{'name': 'base64', 'cat': ['encryption']},
{'name': 'json', 'cat': ['conversion', 'serialize']},
{'name': 'url', 'cat': ['conversion']},
{'name': 'timestamp', 'cat': ['conversion']},
{'name': 'qrCode', 'cat': ['generate']},
{'name': 'pinyin', 'cat': ['conversion']},
{'name': 'ip', 'cat': ['other']},
{'name': 'code', 'cat': ['other']},
{'name': 'unicode', 'cat': ['conversion']},
{'name': 'decimalConvert', 'cat': ['conversion']},
{'name': 'regex', 'cat': ['check']},
{'name': 'randomString', 'cat': ['generate']},
{'name': 'serializeConversion', 'cat': ['conversion', 'serialize']},
{'name': 'diffs', 'cat': ['check']},
{'name': 'crontab', 'cat': ['check']},
{'name': 'websocket', 'cat': ['other']},
{'name': 'unit', 'cat': ['other']},
{'name': 'time', 'cat': ['other']},
{'name': 'uuid', 'cat': ['generate']},
{'name': 'jsonToObject', 'cat': ['conversion', 'serialize']},
{'name': 'ascii', 'cat': ['conversion']},
{'name': 'variableConversion', 'cat': ['conversion']},
{'name': 'jwt', 'cat': ['conversion']},
{'name': 'hexString', 'cat': ['conversion']},
{'name': 'text', 'cat': ['other']},
{'name': 'html', 'cat': ['conversion']},
]
// 工具类功能配置
......
locales/build.json
// 编译语言包
const path = require('path');
const fs = require('fs');
const JSON5 = require('json5')
const _ = require('lodash')
const LOCAL_LISTS = [
{code: '_default', name: "默认(default)"},
{code: "en", name: "English"},
{code: 'zh_CN', name: "简体中文"}
]
const DEFAULT_LOCALE = 'zh_CN'
const codeToLocale = (code) => {
return code === "_default" ? DEFAULT_LOCALE : code;
}
const placeholder = (message) => {
let placeholders = [];
const result = message.match(new RegExp('{.+?}', 'g'));
if (result !== null) {
result.forEach((item) => {
item = item.replace('{', '').replace('}', '')
if (!placeholders.includes(item)) {
placeholders.push(item)
}
})
}
return placeholders
}
const getLocale = (code) => {
const localeDir = path.join(__dirname, "locales/" + code)
if (!(fs.existsSync(localeDir) && fs.statSync(localeDir).isDirectory())) {
return null;
}
let locale = {}
fs.readdirSync(path.resolve(localeDir)).forEach((file) => {
if (file.indexOf('.i18n.json5') !== -1) {
let type = file.replace('.i18n.json5', '');
let config = JSON5.parse(fs.readFileSync(path.join(__dirname, `locales/${code}/${file}`), 'utf-8'));
Object.keys(config).forEach(function (key) {
let placeholders = placeholder(config[key])
locale[`${type}_${key}`] = {
message: config[key],
}
if (placeholders.length > 0) {
locale["placeholders"] = placeholders
}
});
}
})
return locale;
}
const getAllLocale = () => {
// 所有语言包
let locales = {
lists: LOCAL_LISTS,
default_locale: DEFAULT_LOCALE,
detail: {}
}
fs.readdirSync(path.resolve(path.join(__dirname, "locales"))).forEach((code) => {
let locale = getLocale(code)
if (locale !== null) {
locales['detail'][code] = locale;
}
})
checkAllLocale(locales)
return locales
}
const checkAllLocale = (locales) => {
/**
* 检查语言包是否完备
* 确保中文/英文语言包是否一致
*/
const zhKeys = Object.keys(locales['detail']['zh_CN'])
const enKeys = Object.keys(locales['detail']['en'])
const zhDiff = _.difference(zhKeys, enKeys);
if (zhDiff.length > 0) {
throw new Error(`中/英文语言包存在差异[key](英文缺失):${zhDiff.join(',')}`)
}
const enDiff = _.difference(enKeys, zhKeys);
if (enDiff.length > 0) {
throw new Error(`中/英文语言包存在差异[key](中文缺失):${enDiff.join(',')}`)
}
}
const ALL_LOCALE = getAllLocale()
module.exports = {
getLocales() {
return ALL_LOCALE;
},
// 生成运行时语言包
generate() {
fs.writeFileSync(path.join(__dirname, 'locales/build.json'), JSON.stringify(ALL_LOCALE, null, 4));
},
getMessage(code, key) {
let locales = ALL_LOCALE['detail']
let locale = codeToLocale(code)
let text = key;
if ((locale in locales) && (key in locales[locale])) {
text = locales[locale][key]['message']
} else if (locale !== DEFAULT_LOCALE) {
// 获取默认语言
text = this.getMessage(DEFAULT_LOCALE, key)
}
return text;
},
translate(key, values = {}, code = DEFAULT_LOCALE) {
if (!key) return '';
const text = this.getMessage(code, key)
const matchRge = new RegExp('{.+?}', 'g')
const matchString = text.match(matchRge);
const replaceHash = {};
// 获取语言包对应翻译内容
let result = text;
if (matchString) {
matchString.forEach((wildcard) => {
if ((wildcard in values) && !(wildcard in replaceHash)) {
replaceHash[wildcard] = values[wildcard]
}
});
}
result = result.replace(matchRge, (replacer) => {
return replacer in replaceHash ? replaceHash[replacer] : replacer;
});
return result;
}
}
import VueI18n from 'vue-i18n'
import Vue from 'vue'
import {getMessage as chromiumGetMessage} from "../adapter/chromium/helper"
import {isChromium} from "../helper";
Vue.use(VueI18n)
const locales = require('./locales/build.json')
// 区域列表
export const LOCALE_LISTS = locales.lists
export const LOCALE_DETAIL = locales.detail
export const DEFAULT_LOCALE = locales.default_locale
let currentLocale = "";
// 设置当前地区
export const setCurrentLocale = (locale) => {
currentLocale = locale;
}
const getMessage = (code, key) => {
let locale = code === "_default" ? DEFAULT_LOCALE : code;
let text = key;
if ((locale in LOCALE_DETAIL) && (key in LOCALE_DETAIL[locale])) {
text = LOCALE_DETAIL[locale][key]['message']
}
else if(locale !== DEFAULT_LOCALE){
// 获取默认语言
text = getMessage(DEFAULT_LOCALE,key)
}
return text;
}
const translate = (code, key, values = {}) => {
if (!key) return '';
let locale = code === "_default" ? DEFAULT_LOCALE : code;
if (isChromium && code === "_default") {
let placeholders = []
if (
(locale in LOCALE_DETAIL)
&& (key in LOCALE_DETAIL[locale])
&& ('placeholders' in LOCALE_DETAIL[locale][key])
) {
placeholders = LOCALE_DETAIL[locale][key]['placeholders']
}
return chromiumGetMessage(key, values, placeholders)
}
let text = getMessage(code,key);
const matchRge = new RegExp('{.+?}', 'g')
const matchString = text.match(matchRge);
const replaceHash = {};
// 获取语言包对应翻译内容
let result = text;
if (matchString) {
matchString.forEach((wildcard) => {
if ((wildcard in values) && !(wildcard in replaceHash)) {
replaceHash[wildcard] = values[wildcard]
}
});
}
result = result.replace(matchRge, (replacer) => {
return replacer in replaceHash ? replaceHash[replacer] : replacer;
});
return result;
}
window["__"] = (key, values = {}, locale = null) => {
locale = !locale ? currentLocale : locale
// values 必须是对象
return translate(
(!locale ? currentLocale : locale),
key,
values
)
}
export const i18n = new VueI18n({
locale: 'zh_CN',
missing: (locale, key, vm, values) => {
if (Array.isArray(values) && values.length === 1) {
if (Array.isArray(values[0])) {
// 数组转对象表示法
let temp = {}
for (let i = 0; i < values[0].length; i++) {
temp[i] = values[0][i]
}
return __(key, temp)
}
return __(key, values[0])
}
return __(key)
}
})
{
// ui
"ui_setting": "Settings",
"ui_views": "View",
"ui_load":"Loading",
"ui_close": "Close",
// views
"setting_language": "Language",
"common_tool": "Common Tool",
"keyboard_setting":"Setting Shortcuts",
"display_mode": "Theme",
"display_mode_light":"Light",
"display_mode_dark":"Dark",
"display_mode_auto":"Auto",
"copy_results_to_clipboard":"Copy results to clipboard",
"read_content_from_clipboard": "Read content from clipboard",
"read_clipboard_content_trim":"Read clipboard content trim",
"common_tool_setting": "Common Tool Settings",
"keyboard_firefox_1":"Need to manually set shortcuts",
"keyboard_firefox_2": "Open [Add-ons Manager(about:addons)],Click the setting button on the right side of [Manage your extension],Select [Manage Extension Shortcuts] to modify these shortcuts.",
"keyboard_firefox_3":"Operation Method",
"history": "History",
"history_clear": "Clear history",
"history_time": "Operation time",
"history_data":"Data",
"history_op": "Operation",
"history_null":"History not found",
// category
"category_common": "Common",
"category_encryption": "En/Decrypt",
"category_conversion": "Convert",
"category_serialize": "Serialize",
"category_check": "Validator",
"category_generate": "Generate",
"category_other": "Other",
// tool
"tool_hash": "Hash",
"tool_encrypt": "Encrypt & Decrypt",
"tool_sign": "Sign",
"tool_base64": "Base64",
"tool_json": "JSON",
"tool_url": "Url En/Decode",
"tool_timestamp": "Timestamp",
"tool_qrCode": "QR Code",
"tool_pinyin": "Chinese Pinyin",
"tool_ip": "Ip Query",
"tool_code": "Code Formatter ",
"tool_unicode": "Unicode",
"tool_decimalConvert": "Base Convert",
"tool_regex": "Regex",
"tool_randomString": "Random String",
"tool_serializeConversion": "Serialize Convert",
"tool_diffs": "Compare Text",
"tool_crontab": "Crontab",
"tool_websocket": "Websocket",
"tool_unit": "Unit Convert",
"tool_time": "Time Calculator",
"tool_uuid": "UUID",
"tool_jsonToObject": "JSON to Object",
"tool_ascii": "ASCII",
"tool_variableConversion": "Variable Name",
"tool_jwt": "JWT",
"tool_hexString": "Hex/String",
"tool_text": "Text",
"tool_html": "Html En/Decode",
// other
"css_main_category_item_style": "padding: 0 10px"
}
{
// ui
"ui_setting": "设置",
"ui_views": "查看",
"ui_load":"加载",
"ui_close": "管理",
// 界面
"setting_language": "语言",
"common_tool": "常用工具",
"keyboard_setting":"快捷键设置",
"display_mode": "主题",
"display_mode_light":"浅色",
"display_mode_dark":"深色",
"display_mode_auto":"自动",
"copy_results_to_clipboard":"自动复制结果到剪贴板",
"read_content_from_clipboard": "自动读取剪贴板内容",
"read_clipboard_content_trim":"读取剪贴板内容过滤首尾不可见字符",
"common_tool_setting": "常用工具设置",
"keyboard_firefox_1":"请手动设置快捷键",
"keyboard_firefox_2": "请打开附加组件管理器(about:addons),点击“管理扩展程序”右侧的设置按钮,选择“管理扩展快捷键”来修改这些快捷键。",
"keyboard_firefox_3":"操作方法",
"history": "历史记录",
"history_clear": "清空历史记录",
"history_time": "操作时间",
"history_data":"数据",
"history_op": "操作",
"history_null":"暂无历史记录",
// 分类
"category_common": "常用",
"category_encryption": "加解密",
"category_conversion": "转换",
"category_serialize": "序列化",
"category_check": "校验",
"category_generate": "生成",
"category_other": "其他",
// 工具
"tool_hash": "哈希(hash)",
"tool_encrypt": "加密/解密",
"tool_sign": "签名/验签",
"tool_base64": "BASE64编码",
"tool_json": "JSON工具",
"tool_url": "URL编码",
"tool_timestamp": "时间戳",
"tool_qrCode": "二维码",
"tool_pinyin": "汉字转拼音",
"tool_ip": "IP地址查询",
"tool_code": "代码格式化",
"tool_unicode": "Unicode",
"tool_decimalConvert": "进制转换",
"tool_regex": "正则表达式",
"tool_randomString": "随机字符生成",
"tool_serializeConversion": "序列化转换",
"tool_diffs": "文本差异化对比",
"tool_crontab": "crontab校验",
"tool_websocket": "websocket调试",
"tool_unit": "单位换算",
"tool_time": "时间计算器",
"tool_uuid": "UUID生成",
"tool_jsonToObject": "JSON转实体类",
"tool_ascii": "ASCII转换",
"tool_variableConversion": "变量名转换",
"tool_jwt": "JWT解码",
"tool_hexString": "Hex/String转换",
"tool_text": "文本处理",
"tool_html": "html编码",
// 其他
"css_main_category_item_style": "padding: 0 20px"
}
......@@ -8,8 +8,11 @@ import cache from './tool/cache'
import setting from './tool/setting'
import App from './tool.vue'
import {isUtools,setDisplayMode} from './helper'
import {setCurrentLocale,i18n} from "./i18n";
const run = () => {
// 设置语言环境
setCurrentLocale(setting.locale())
// 设置显示模式
setDisplayMode(setting.displayMode())
......@@ -20,6 +23,7 @@ const run = () => {
Vue.component('option-block', optionBlock);
new Vue({
i18n,
router,
render: h => h(App),
}).$mount('#app')
......
......@@ -2,12 +2,12 @@
<div>
<Menu mode="horizontal" theme="light" :active-name="currentCategory" @on-select="categorySelect"
style="height: 45px;line-height: 45px;">
<MenuItem :name="cat.name" v-for="(cat) in category" :key="cat.name">
<MenuItem :style="$t('mian_css_main_category_item_style')" :name="cat.name" v-for="(cat) in category" :key="cat.name">
<Badge v-if="badgeCategoryIsShow(cat.name)" dot :offset="[15,-10]">
{{ cat.title }}
{{ $t('mian_category_'+cat.name) }}
</Badge>
<template v-else>
{{ cat.title }}
{{ $t('mian_category_'+cat.name) }}
</template>
</MenuItem>
<MenuItem style="padding: 0 5px;float: right" name="_new" v-if="!isUtools">
......@@ -34,31 +34,31 @@
<RadioGroup :value="currentTool" @on-change="toolSelect" style="margin: 10px 0 10px 20px;line-height: 30px;">
<Radio :label="tool.name" v-for="(tool) in tools" :key="tool.name">
<Badge v-if="badgeToolIsShow(tool.name)" dot :offset="[5,-5]">
{{ tool.title }}
{{ $t('mian_tool_'+tool.name) }}
</Badge>
<template v-else>
{{ tool.title }}
{{ $t('mian_tool_'+tool.name) }}
</template>
</Radio>
</RadioGroup>
<div>
<router-view v-if="isRouterAlive" :key="$route.path + $route.query.t"/>
</div>
<Drawer :title="currentToolTitle+' - 历史记录'" v-model="historyShow" :width="100">
<Drawer :title="$t('mian_tool_'+currentTool)+' - '+$t('mian_history')" v-model="historyShow" :width="100">
<Table ref="historyTable" border :columns="historyColumns" :data="historyData" :height="historyTableHeight">
<template slot-scope="{ row }" slot="_value">
<div>{{ historyValue(row.value) }}}</div>
</template>
<template slot-scope="{ index }" slot="_op">
<Button type="primary" size="small" @click="historyView(index)">查看</Button>
<Button type="primary" style="margin-left: 5px" @click="historyLoad(index)" size="small">加载</Button>
<Button type="primary" size="small" @click="historyView(index)">{{ $t('mian_ui_views') }}</Button>
<Button type="primary" style="margin-left: 5px" @click="historyLoad(index)" size="small">{{ $t('mian_ui_load') }}</Button>
</template>
</Table>
<div class="drawer-footer">
<Button type="primary" @click="historyClear">清空历史记录</Button>
<Button type="primary" @click="historyClear">{{ $t('mian_history_clear') }}</Button>
</div>
</Drawer>
<Drawer title="设置" v-model="settingShow" :width="400">
<Drawer :title="$t('mian_ui_setting')" v-model="settingShow" :width="400">
<setting-block v-if="settingShow"></setting-block>
</Drawer>
<bottom-block/>
......@@ -91,17 +91,17 @@ export default {
historyShow: false,
historyColumns: [
{
title: '操作时间',
title: this.$t('mian_history_time'),
key: 'time',
width: 180
},
{
title: '数据',
title: this.$t('mian_history_data'),
slot: '_value',
ellipsis: true,
},
{
title: '操作',
title: this.$t('mian_history_op'),
slot: '_op',
width: 150
}
......@@ -118,9 +118,6 @@ export default {
historyTableHeight() {
// 设置表格高度
return window.innerHeight - 140
},
currentToolTitle() {
return config.getToolTitle(this.currentTool)
}
},
watch: {
......@@ -207,7 +204,7 @@ export default {
history() {
let history = historyFactory(this.currentTool)
if (history.length() < 1) {
return this.$Message.error('暂无历史记录')
return this.$Message.error(this.$t('mian_history_null'))
}
this.historyData = history.all()
this.historyShow = true
......@@ -227,7 +224,7 @@ export default {
})
},
width: 700,
okText: "关闭"
okText: this.$t('mian_ui_close')
})
},
historyClear() {
......@@ -268,4 +265,4 @@ export default {
text-align: right;
background: #fff;
}
</style>
\ No newline at end of file
</style>
const path = require('path');
const _ = require('lodash');
const fs = require('fs');
const i18nBuild = require('../i18n/build')
// 运行平台适配
let platform = process.env.hasOwnProperty('npm_config_adapter') ? process.env.npm_config_adapter : "";
platform = ['chrome', 'utools', 'edge', 'firefox','web'].includes(platform) ? platform : "web"
platform = ['chrome', 'utools', 'edge', 'firefox', 'web'].includes(platform) ? platform : "web"
const IS_CHROME = "chrome" === platform
const IS_EDGE = "edge" === platform
......@@ -31,10 +32,26 @@ const removeFile = (filePath) => {
fs.existsSync(filePath) && fs.unlinkSync(filePath)
}
// 删除目录
const removeDir = function (directoryPath) {
if (fs.existsSync(directoryPath)) {
fs.readdirSync(directoryPath).forEach((file) => {
const curPath = path.join(directoryPath, file);
if (fs.lstatSync(curPath).isDirectory()) {
removeDir(curPath);
} else {
fs.unlinkSync(curPath);
}
});
fs.rmdirSync(directoryPath);
}
};
const chromeConfigWrite = {
remove(){},
write(){
if (!IS_CHROME){
remove() {
},
write() {
if (!IS_CHROME) {
return;
}
fs.writeFileSync(
......@@ -45,9 +62,10 @@ const chromeConfigWrite = {
}
const edgeConfigWrite = {
remove(){},
write(){
if (!IS_EDGE){
remove() {
},
write() {
if (!IS_EDGE) {
return;
}
fs.writeFileSync(
......@@ -58,28 +76,54 @@ const edgeConfigWrite = {
}
const chromiumConfigWrite = {
remove(){
remove() {
removeFile(path.join(__dirname, '../../public/manifest.json'));
removeFile(path.join(__dirname, '../../public/background.js'));
// 移除语言包目录
removeDir(path.join(__dirname, '../../public/_locales/'))
},
write(){
if (!IS_CHROMIUM){
write() {
if (!IS_CHROMIUM) {
return;
}
fs.copyFileSync(
path.join(__dirname, "../adapter/chromium/background.js"),
path.join(__dirname, '../../public/background.js')
);
// 生成语言包
const locales = i18nBuild.getLocales()
const localeDir = path.join(__dirname, '../../public/_locales/')
fs.mkdirSync(localeDir);
Object.keys(locales).forEach((_locale) => {
fs.mkdirSync(path.join(localeDir, _locale));
let messages = {}
Object.keys(locales[_locale]).forEach((key) => {
let message = {
message: locales[_locale][key]['message'].replace(new RegExp("{.+?}", 'g'), (item) => {
return `$${item.replace("{", "").replace("}", "").toUpperCase()}$`;
})
}
if ("placeholders" in locales[_locale][key]) {
message.placeholders = {}
let index = 1;
locales[_locale][key]['placeholders'].forEach((placeholder) => {
message.placeholders[placeholder] = {content: "$" + (index++)}
})
}
messages[key] = message
})
fs.writeFileSync(path.join(localeDir, `${_locale}/messages.json`), JSON.stringify(messages, null, 4));
})
}
}
const firefoxConfigWrite ={
remove(){
const firefoxConfigWrite = {
remove() {
removeFile(path.join(__dirname, '../../public/manifest.json'));
removeFile(path.join(__dirname, '../../public/background.js'));
},
write(){
if (!IS_FIREFOX){
write() {
if (!IS_FIREFOX) {
return;
}
fs.copyFileSync(
......@@ -94,13 +138,12 @@ const firefoxConfigWrite ={
}
const utoolsConfigWrite = {
remove(){
remove() {
removeFile(path.join(__dirname, '../../public/plugin.json'));
},
write(){
if (!IS_UTOOLS){
write() {
if (!IS_UTOOLS) {
return;
}
let pluginPath = path.join(__dirname, '../../public/plugin.json');
......@@ -110,11 +153,12 @@ const utoolsConfigWrite = {
for (let tool of tools) {
// 初始化数据
let code = "ctool-" + tool.name;
let toolTitle = i18nBuild.translate(`mian_tool_${tool.name}`)
let toolFeatures = featureConfig.hasOwnProperty(tool.name) ? featureConfig[tool.name] : []
if (!utoolsToolFeature.hasOwnProperty(code)) {
utoolsToolFeature[code] = {
"code": code,
"explain": tool.title,
"explain": toolTitle,
"cmds": []
}
if (toolFeatures.length > 0) {
......@@ -122,7 +166,7 @@ const utoolsConfigWrite = {
let toolFeatureCode = code + '-' + toolFeature['name']
utoolsToolFeature[toolFeatureCode] = {
"code": toolFeatureCode,
"explain": tool.title + ' - ' + toolFeature['title'],
"explain": toolTitle + ' - ' + toolFeature['title'],
"cmds": []
}
}
......@@ -132,7 +176,7 @@ const utoolsConfigWrite = {
// 关键字
let keyword = utoolsConfig['keyword'].hasOwnProperty(tool.name) ? utoolsConfig['keyword'][tool.name] : []
utoolsToolFeature[code].cmds.push(
...Array.from(new Set([tool.name, tool.title, "ctool-" + tool.name, ...keyword]))
...Array.from(new Set([tool.name, toolTitle, "ctool-" + tool.name, ...keyword]))
)
// cmds手动配置
......@@ -144,13 +188,13 @@ const utoolsConfigWrite = {
for (let _cmd of cmds) {
let cmd = _.cloneDeep(_cmd);
if (!cmd.hasOwnProperty('feature')) {
cmd['label'] = tool.title
cmd['label'] = toolTitle
utoolsToolFeature[code].cmds.push(cmd)
continue;
}
let toolFeatureCode = code + '-' + cmd.feature
if (utoolsToolFeature.hasOwnProperty(toolFeatureCode)) {
cmd['label'] = tool.title + ' - ' + getToolFeatureTitle(cmd.feature, toolFeatures)
cmd['label'] = toolTitle + ' - ' + getToolFeatureTitle(cmd.feature, toolFeatures)
delete cmd.feature
utoolsToolFeature[toolFeatureCode].cmds.push(cmd)
}
......@@ -195,5 +239,7 @@ module.exports = {
edgeConfigWrite.write();
firefoxConfigWrite.write();
utoolsConfigWrite.write();
// 生成运行时语言包
i18nBuild.generate()
}
}
......@@ -36,7 +36,7 @@ const setUserCommon = function (tools) {
const getToolTitle = function (name) {
for (let i = 0; i < tool.length; i++) {
if (tool[i].name === name) {
return tool[i].title
return __()
}
}
return ''
......@@ -74,12 +74,11 @@ const saveSetting = function (name, value) {
}
export default {
tool,
tool:tool,
saveSetting,
getSetting,
category,
setUserCommon,
getToolTitle,
getUserCommon,
getToolByCategory(cat) {
let common = getUserCommon();
......@@ -97,4 +96,4 @@ export default {
badgeCategoryIsShow(cat) {
return badgeIsShow() && BADGE_CATEGORY.includes(cat)
},
}
\ No newline at end of file
}
......@@ -42,4 +42,14 @@ export default {
}
return config.saveSetting('display_mode', value)
},
/**
* @param value
* @return {boolean}
*/
locale(value = null) {
if (value === null) {
return config.getSetting('locale', '_default')
}
return config.saveSetting('locale', value)
},
}
......@@ -2,27 +2,32 @@
<div>
<div>
<CellGroup @on-click="open">
<Cell title="常用工具设置" name="setting"/>
<Cell v-if="is_chromium || is_firefox" title="快捷键设置" name="shortcuts"/>
<Cell title="外观显示">
<Cell :title="$t('mian_common_tool')" name="setting"/>
<Cell v-if="is_chromium || is_firefox" :title="$t('mian_keyboard_setting')" name="shortcuts"/>
<Cell :title="$t('mian_display_mode')">
<Select v-model="display_mode" slot="extra" transfer>
<Option v-for="item in display_mode_list" :value="item.v" :key="item.v">{{ item.n }}</Option>
<Option v-for="item in display_mode_list" :value="item" :key="item">{{ $t('mian_display_mode_'+item)}}</Option>
</Select>
</Cell>
<Cell :title="$t('mian_setting_language')">
<Select v-model="locale" slot="extra" transfer>
<Option v-for="item in locales" :value="item.code" :key="item.code">{{ item.name }}</Option>
</Select>
</Cell>
</CellGroup>
<CellGroup>
<Cell title="自动复制结果到剪贴板">
<Cell :title="$t('mian_copy_results_to_clipboard')">
<i-switch v-model="auto_save_copy" slot="extra"/>
</Cell>
<Cell title="自动读取剪贴板内容">
<Cell :title="$t('mian_read_content_from_clipboard')">
<i-switch v-model="auto_read_copy" slot="extra"/>
</Cell>
<Cell title="读取剪贴板内容过滤首尾不可见字符">
<Cell :title="$t('mian_read_clipboard_content_trim')">
<i-switch v-model="auto_read_copy_filter" slot="extra"/>
</Cell>
</CellGroup>
</div>
<Drawer title="设置" placement="left" v-model="settingShow" :width="90">
<Drawer :title="$t('mian_ui_setting')" placement="left" v-model="settingShow" :width="90">
<setting-block v-if="settingShow"></setting-block>
</Drawer>
</div>
......@@ -30,6 +35,7 @@
<script>
import {isChromium, isFirefox, isUtools, openUrl, setDisplayMode} from '../../helper'
import {LOCALE_LISTS, setCurrentLocale} from '../../i18n'
import setting from '../../tool/setting'
import settingBlock from './setting'
......@@ -47,16 +53,17 @@ export default {
is_chromium: isChromium,
is_utools: isUtools,
is_firefox: isFirefox,
display_mode_list: [
{n: "浅色", v: "light"},
{n: "深色", v: "dark"},
{n: "自动", v: "auto"},
]
display_mode_list: ["light","dark","auto"],
locales: LOCALE_LISTS,
locale: "",
}
},
watch: {
display_mode(value) {
setDisplayMode(value)
},
locale(value) {
setCurrentLocale(value)
}
},
created() {
......@@ -64,12 +71,14 @@ export default {
this.auto_read_copy = setting.autoReadCopy()
this.auto_read_copy_filter = setting.autoReadCopyFilter()
this.display_mode = setting.displayMode()
this.locale = setting.locale()
},
beforeDestroy() {
setting.autoSaveCopy(this.auto_save_copy)
setting.autoReadCopy(this.auto_read_copy)
setting.autoReadCopyFilter(this.auto_read_copy_filter)
setting.displayMode(this.display_mode)
setting.locale(this.locale)
},
methods: {
open(name) {
......@@ -77,16 +86,16 @@ export default {
case 'shortcuts':
if (this.is_firefox) {
return this.$Notice.success({
title: '请手动设置快捷键',
title: this.$t('mian_keyboard_firefox_1'),
render: h => {
return h('span', [
'请打开附加组件管理器(about:addons),点击“管理扩展程序”右侧的设置按钮,选择“管理扩展快捷键”来修改这些快捷键。',
this.$t('mian_keyboard_firefox_2'),
h('a', {
attrs: {
href: 'https://jingyan.baidu.com/article/3ea51489f1d0a713e61bbaff.html',
target: '_blank'
}
}, '操作方法'),
}, this.$t('mian_keyboard_firefox_3')),
])
}
});
......
<template>
<div>
<CheckboxGroup v-model="tools" @on-change="toolUpdate" style="line-height: 30px;">
<Checkbox v-for="(t,k) in all" :key="k" :label="t.name">{{t.title}}</Checkbox>
<Checkbox v-for="(t,k) in all" :key="k" :label="t.name">{{$t('mian_tool_'+t.name)}}</Checkbox>
</CheckboxGroup>
</div>
</template>
......@@ -28,4 +28,4 @@
},
},
}
</script>
\ No newline at end of file
</script>
<template>
<Card>
<Tabs value="common">
<TabPane label="常用工具设置" name="common">
<TabPane :label="$t('mian_common_tool_setting')" name="common">
<setting-common></setting-common>
</TabPane>
</Tabs>
......@@ -14,4 +14,4 @@
"setting-common": common
}
}
</script>
\ No newline at end of file
</script>
<template>
<div>
<div style="border: 1px solid #dcdee2;border-radius: 4px;">
<code-editor v-model="current.content" :auto-height="220" language="json"></code-editor>
<div>
<div style="border: 1px solid #dcdee2;border-radius: 4px;">
<code-editor v-model="current.content" :auto-height="220" language="json"></code-editor>
</div>
<option-block :style="{textAlign:'center'}">
<FormItem>
<ButtonGroup class="tool-json-button">
<Button type="primary" @click="handle(k)" v-for="(v,k) in type" :key="k">{{ v }}</Button>
</ButtonGroup>
</FormItem>
</option-block>
</div>
<option-block :style="{textAlign:'center'}">
<FormItem>
<ButtonGroup>
<Button type="primary" @click="handle(k)" v-for="(v,k) in type" :key="k">{{v}}</Button>
</ButtonGroup>
</FormItem>
</option-block>
</div>
</template>
<script>
import Unicode from "./library/unicode"
import codeEditor from "./components/codeEditor";
import Unicode from "./library/unicode"
import {jsonFormatter} from "./library/formatter"
import codeEditor from "./components/codeEditor";
export default {
components: {
codeEditor,
},
created () {
this.current = Object.assign(this.current, this.$getToolData('content'))
},
methods: {
handle (v) {
if (this.current.content) {
switch (v) {
case 'format':
try {
let content = this.current.content.trim()
if (!content) {
return this.$Notice.error({ title: '错误提示', desc: '请输入内容' })
}
require('jsonlint').parse(content)
this.current.content = JSON.stringify(JSON.parse(this.current.content), null, 4)
} catch (error) {
this.$Notice.error({
title: '错误提示',
desc: error.message,
})
return
export default {
components: {
codeEditor,
},
created() {
this.current = Object.assign(this.current, this.$getToolData('content'))
},
methods: {
handle(v) {
if (this.current.content) {
// 保存操作前数据
this.$saveToolData(this.current)
switch (v) {
case 'format':
try {
let content = this.current.content.trim()
if (!content) {
return this.$Notice.error({title: '错误提示', desc: '请输入内容'})
}
break
case 'compress':
try {
this.current.content = JSON.stringify(JSON.parse(this.current.content.trim()))
} catch (e) {
this.current.content = this.current.content.replace(/\n/g, '').replace(/\r/g, '')
require('jsonlint').parse(content)
this.current.content = jsonFormatter(content)
} catch (error) {
this.$Notice.error({
title: '错误提示',
desc: error.message,
})
return
}
break
case 'compress':
try {
this.current.content = JSON.stringify(JSON.parse(this.current.content.trim()))
} catch (e) {
this.current.content = this.current.content.replace(/\n/g, '').replace(/\r/g, '')
}
break
case 'escape':
this.current.content = this.current.content.trim().replace(/\\/g, '\\\\').replace(/"/g, '\\"')
break
case 'clearEscape':
this.current.content = this.current.content.trim().replace(/\\\\/g, '\\').replace(/\\"/g, '"')
break
case 'unicode2zh':
this.current.content = this.unicode2zh()
break
case 'zh2unicode':
this.current.content = this.zh2unicode()
break
case 'get':
try {
let content = this.current.content.trim()
if (!content) {
return
}
break
case 'escape':
this.current.content = this.current.content.trim().
replace(/\\/g, '\\\\').
replace(/"/g, '\\"')
break
case 'clearEscape':
this.current.content = this.current.content.trim().
replace(/\\\\/g, '\\').
replace(/\\"/g, '"')
break
case 'unicode2zh':
this.current.content = this.unicode2zh()
break
case 'zh2unicode':
this.current.content = this.zh2unicode()
break
case 'get':
try {
const httpBuildQuery = require('http-build-query');
let content = this.current.content.trim()
if (!content) {
return
}
require('jsonlint').parse(content)
this.current.content = httpBuildQuery(JSON.parse(this.current.content))
} catch (error) {
this.$Notice.error({
title: '错误提示',
desc: error.message,
})
require('jsonlint').parse(content)
this.current.content = require('query-string').stringify(
JSON.parse(this.current.content), {arrayFormat: 'bracket'}
)
} catch (error) {
this.$Notice.error({
title: '错误提示',
desc: error.message,
})
return
}
break
case 'getToJson':
try {
let content = this.current.content.trim()
if (!content) {
return
}
break
case 'clear':
this.current.content = ''
break
default:
this.current.content = jsonFormatter(
JSON.stringify(require('query-string').parse(content, {arrayFormat: 'bracket'}))
)
} catch (error) {
this.$Notice.error({
title: '错误提示',
desc: error.message,
})
return
}
this.$clipboardCopy(this.current.content)
this.$saveToolData(this.current)
}
break
case 'clear':
this.current.content = ''
break
default:
return
}
},
unicode2zh () {
return Unicode.decode(
this.current.content.replace(/\\U[0-9a-fA-F]{4}/g,(item)=>{
// \Uxxxx=>\uxxxx
return item.replace("\\U","\\u");
})
)
},
zh2unicode () {
let content = this.current.content
if (content) {
let newStr = ''
for (let i = 0; i < content.length; i++) {
let str = content.charAt(i)
newStr += /[\u4e00-\u9fa5]/.test(str) ? '\\u' + str.charCodeAt(0).toString(16) : str
}
return newStr
}
return content
},
},
data () {
return {
current: {
content: '',
},
type: {
'format': '格式化/校验',
'compress': '压缩',
'escape': '转义',
'clearEscape': '去除转义',
'unicode2zh': 'Unicode转中文',
'zh2unicode': '中文转Unicode',
'get': '转GET参数',
'clear': '清空数据',
},
this.$clipboardCopy(this.current.content)
this.$saveToolData(this.current)
}
},
}
unicode2zh() {
return Unicode.decode(
this.current.content.replace(/\\U[0-9a-fA-F]{4}/g, (item) => {
// \Uxxxx=>\uxxxx
return item.replace("\\U", "\\u");
})
)
},
zh2unicode() {
let content = this.current.content
if (content) {
let newStr = ''
for (let i = 0; i < content.length; i++) {
let str = content.charAt(i)
newStr += /[\u4e00-\u9fa5]/.test(str) ? '\\u' + str.charCodeAt(0).toString(16) : str
}
return newStr
}
return content
}
},
data() {
return {
current: {
content: '',
},
type: {
'format': '格式化',
'compress': '压缩',
'escape': '转义',
'clearEscape': '去除转义',
'unicode2zh': 'Unicode转中文',
'zh2unicode': '中文转Unicode',
'get': '转GET',
'getToJson': 'GET转Json',
'clear': '清空',
},
}
},
}
</script>
<style scoped>
.tool-json-button .ivu-btn{
padding: 0 10px;
}
</style>
......@@ -31,11 +31,25 @@ const options = {
php: {parser: "php", plugins: [parserPhp]},
java: {parser: "java", plugins: [parserJava]},
};
export default (code, lang, {tab = 4}) => {
const format = (code, lang, formatOptions = {}) => {
if (!(lang in options)) {
throw new Error(`${lang} can't format`);
}
let tab = "tab" in formatOptions ? formatOptions.tab : 4;
let langOption = options[lang];
langOption.tabWidth = tab
if ("printWidth" in formatOptions){
langOption.printWidth = formatOptions.printWidth
}
if ("proseWrap" in formatOptions){
langOption.proseWrap = formatOptions.proseWrap
}
return prettier.format(code, langOption);
};
export default format
export const jsonFormatter = (code) => {
return format(code, 'json', {printWidth: 2, proseWrap: "never"})
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册