diff --git a/package.json b/package.json index 7db3d7c..a9f8feb 100644 --- a/package.json +++ b/package.json @@ -35,17 +35,18 @@ ] }, "dependencies": { + "@picgo/i18n": "^0.0.4", "@picgo/store": "^1.0.3", "axios": "^0.19.0", "core-js": "^3.3.2", "element-ui": "^2.13.0", - "fix-path": "^4.0.0", "fs-extra": "^10.0.0", "keycode": "^2.2.0", "lodash-id": "^0.14.0", "lowdb": "^1.0.0", "picgo": "^1.5.0-alpha.0", "qrcode.vue": "^1.7.0", + "shell-path": "2.1.0", "uuidv4": "^6.2.11", "vue": "^2.6.10", "vue-gallery": "^2.0.1", diff --git a/src/main/apis/app/system/index.ts b/src/main/apis/app/system/index.ts index effe175..34c8ecf 100644 --- a/src/main/apis/app/system/index.ts +++ b/src/main/apis/app/system/index.ts @@ -17,6 +17,7 @@ import pasteTemplate from '~/main/utils/pasteTemplate' import pkg from 'root/package.json' import { handleCopyUrl } from '~/main/utils/common' import { privacyManager } from '~/main/utils/privacyManager' +import { T } from '#/i18n' let contextMenu: Menu | null let menu: Menu | null let tray: Tray | null @@ -41,7 +42,7 @@ export function createContextMenu () { }) contextMenu = Menu.buildFromTemplate([ { - label: '关于', + label: T('ABOUT'), click () { dialog.showMessageBox({ title: 'PicGo', @@ -51,7 +52,7 @@ export function createContextMenu () { } }, { - label: '打开详细窗口', + label: T('OPEN_MAIN_WINDOW'), click () { const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW) settingWindow!.show() @@ -62,14 +63,14 @@ export function createContextMenu () { } }, { - label: '选择默认图床', + label: T('CHOOSE_DEFAULT_PICBED'), type: 'submenu', // @ts-ignore submenu }, // @ts-ignore { - label: '打开更新助手', + label: T('OPEN_UPDATE_HELPER'), type: 'checkbox', checked: db.get('settings.showUpdateTip'), click () { @@ -78,13 +79,13 @@ export function createContextMenu () { } }, { - label: '隐私协议', + label: T('PRIVACY_AGREEMENT'), click () { privacyManager.show(false) } }, { - label: '重启应用', + label: T('RELOAD_APP'), click () { app.relaunch() app.exit(0) @@ -93,7 +94,7 @@ export function createContextMenu () { // @ts-ignore { role: 'quit', - label: '退出' + label: T('QUIT') } ]) } else if (process.platform === 'linux') { @@ -106,7 +107,7 @@ export function createContextMenu () { contextMenu = Menu.buildFromTemplate([ { - label: '打开详细窗口', + label: T('OPEN_MAIN_WINDOW'), click () { const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW) settingWindow!.show() @@ -118,7 +119,7 @@ export function createContextMenu () { }, // @ts-ignore { - label: '打开更新助手', + label: T('OPEN_UPDATE_HELPER'), type: 'checkbox', checked: db.get('settings.showUpdateTip'), click () { @@ -127,7 +128,7 @@ export function createContextMenu () { } }, { - label: '关于应用', + label: T('ABOUT'), click () { dialog.showMessageBox({ title: 'PicGo', @@ -140,7 +141,7 @@ export function createContextMenu () { // @ts-ignore { role: 'quit', - label: '退出' + label: T('QUIT') } ]) } @@ -214,7 +215,7 @@ export function createTray () { for (let i = 0; i < imgs.length; i++) { pasteText.push(pasteTemplate(pasteStyle, imgs[i], db.get('settings.customLink'))) const notification = new Notification({ - title: '上传成功', + title: T('UPLOAD_SUCCESSFULLY'), body: imgs[i].imgUrl!, icon: files[i] }) diff --git a/src/main/lifeCycle/fixPath.ts b/src/main/lifeCycle/fixPath.ts new file mode 100644 index 0000000..ec6526f --- /dev/null +++ b/src/main/lifeCycle/fixPath.ts @@ -0,0 +1,18 @@ +// TODO: so how to import pure esm module in electron main process????? help wanted + +// just copy the fix-path because I can't import pure ESM module in electron main process + +const shellPath = require('shell-path') + +export default function fixPath () { + if (process.platform === 'win32') { + return + } + + process.env.PATH = shellPath.sync() || [ + './node_modules/.bin', + '/.nodebrew/current/bin', + '/usr/local/bin', + process.env.PATH + ].join(':') +} diff --git a/src/main/lifeCycle/index.ts b/src/main/lifeCycle/index.ts index 3f20e3b..1309f27 100644 --- a/src/main/lifeCycle/index.ts +++ b/src/main/lifeCycle/index.ts @@ -34,6 +34,7 @@ import bus from '@core/bus' import { privacyManager } from '~/main/utils/privacyManager' import logger from 'apis/core/picgo/logger' import picgo from 'apis/core/picgo' +import fixPath from './fixPath' const isDevelopment = process.env.NODE_ENV !== 'production' @@ -57,8 +58,6 @@ const handleStartUpFiles = (argv: string[], cwd: string) => { class LifeCycle { private async beforeReady () { protocol.registerSchemesAsPrivileged([{ scheme: 'picgo', privileges: { secure: true, standard: true } }]) - // https://stackoverflow.com/questions/56691391/dynamic-loading-of-external-modules-in-webpack-fails - const fixPath = (await import(/* webpackIgnore: true */ 'fix-path')).default // fix the $PATH in macOS & linux fixPath() beforeOpen() diff --git a/src/universal/i18n/index.ts b/src/universal/i18n/index.ts new file mode 100644 index 0000000..8848553 --- /dev/null +++ b/src/universal/i18n/index.ts @@ -0,0 +1,27 @@ +import { ZH_CN } from './zh-CN' +import { ObjectAdapter, I18n } from '@picgo/i18n' + +const languageList = { + 'zh-CN': ZH_CN +} + +const lowercaseKeys = (obj: any) => + Object.keys(obj).reduce((acc: any, key: string) => { + acc[key.toLowerCase()] = obj[key] + return acc + }, {}) + +// FIXME: @picgo/i18n no lowecase +const objectAdapter = new ObjectAdapter(lowercaseKeys(languageList)) + +const i18n = new I18n({ + adapter: objectAdapter, + defaultLanguage: 'zh-cn' +}) + +// FIXME: @picgo/i18n args should be optional +const T = (key: ILocalesKey, args: IStringKeyMap = {}): string => { + return i18n.translate(key, args)! +} + +export { i18n, T } diff --git a/src/universal/i18n/zh-CN.ts b/src/universal/i18n/zh-CN.ts new file mode 100644 index 0000000..7c622d4 --- /dev/null +++ b/src/universal/i18n/zh-CN.ts @@ -0,0 +1,12 @@ +export const ZH_CN = { + ABOUT: '关于', + OPEN_MAIN_WINDOW: '打开主窗口', + CHOOSE_DEFAULT_PICBED: '选择默认图床', + OPEN_UPDATE_HELPER: '打开更新助手', + PRIVACY_AGREEMENT: '隐私协议', + RELOAD_APP: '重启应用', + UPLOAD_SUCCESSFULLY: '上传成功', + QUIT: '退出' +} + +export type ILocalesKey = keyof typeof ZH_CN diff --git a/src/universal/types/types.d.ts b/src/universal/types/types.d.ts index 451349c..49364aa 100644 --- a/src/universal/types/types.d.ts +++ b/src/universal/types/types.d.ts @@ -335,3 +335,5 @@ interface IMiniWindowPos { } type PromiseResType = T extends Promise ? R : T + +type ILocalesKey = import('#/i18n/zh-CN').ILocalesKey diff --git a/yarn.lock b/yarn.lock index 08396dd..6287edb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1324,6 +1324,13 @@ husky "^1.3.1" ora "^3.4.0" +"@picgo/i18n@^0.0.4": + version "0.0.4" + resolved "https://registry.npmmirror.com/@picgo/i18n/download/@picgo/i18n-0.0.4.tgz#018b0d0999e1d11d6a6f911ee960f7065a9e33a1" + integrity sha1-AYsNCZnh0R1qb5Ee6WD3BlqeM6E= + dependencies: + chalk "^4.0.0" + "@picgo/store@^1.0.3": version "1.0.3" resolved "https://registry.npmjs.org/@picgo/store/-/store-1.0.3.tgz#cfe346ad30c80f378e0bc81311e7468df436bc1f" @@ -2388,11 +2395,6 @@ ansi-regex@^5.0.1: resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-regex@^6.0.1: - version "6.0.1" - resolved "https://registry.npmmirror.com/ansi-regex/download/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" - integrity sha1-MYPjj66aZdfLXlOUXNWJfQJgoGo= - ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -4287,6 +4289,14 @@ create-require@^1.1.0: resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== +cross-spawn@^4.0.0: + version "4.0.2" + resolved "https://registry.npmmirror.com/cross-spawn/download/cross-spawn-4.0.2.tgz#7b9247621c23adfdd3856004a823cbe397424d41" + integrity sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE= + dependencies: + lru-cache "^4.0.1" + which "^1.2.9" + cross-spawn@^5.0.1: version "5.1.0" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" @@ -4771,10 +4781,10 @@ default-gateway@^5.0.5: dependencies: execa "^3.3.0" -default-shell@^2.0.0: - version "2.2.0" - resolved "https://registry.npmmirror.com/default-shell/download/default-shell-2.2.0.tgz#31481c19747bfe59319b486591643eaf115a1864" - integrity sha1-MUgcGXR7/lkxm0hlkWQ+rxFaGGQ= +default-shell@^1.0.0: + version "1.0.1" + resolved "https://registry.npmmirror.com/default-shell/download/default-shell-1.0.1.tgz#752304bddc6174f49eb29cb988feea0b8813c8bc" + integrity sha1-dSMEvdxhdPSespy5iP7qC4gTyLw= default-user-agent@^1.0.0: version "1.0.0" @@ -5709,6 +5719,19 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: md5.js "^1.3.4" safe-buffer "^5.1.1" +execa@^0.5.0: + version "0.5.1" + resolved "https://registry.npmmirror.com/execa/download/execa-0.5.1.tgz?cache=0&sync_timestamp=1637147228297&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fexeca%2Fdownload%2Fexeca-0.5.1.tgz#de3fb85cb8d6e91c85bcbceb164581785cb57b36" + integrity sha1-3j+4XLjW6RyFvLzrFkWBeFy1ezY= + dependencies: + cross-spawn "^4.0.0" + get-stream "^2.2.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + execa@^0.8.0: version "0.8.0" resolved "https://registry.npmjs.org/execa/-/execa-0.8.0.tgz#d8d76bbc1b55217ed190fd6dd49d3c774ecfc8da" @@ -5751,7 +5774,7 @@ execa@^3.3.0: signal-exit "^3.0.2" strip-final-newline "^2.0.0" -execa@^5.0.0, execa@^5.1.1: +execa@^5.0.0: version "5.1.1" resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== @@ -6182,13 +6205,6 @@ findup-sync@^4.0.0: micromatch "^4.0.2" resolve-dir "^1.0.1" -fix-path@^4.0.0: - version "4.0.0" - resolved "https://registry.npmmirror.com/fix-path/download/fix-path-4.0.0.tgz#bc1d14f038edb734ac46944a45454106952ca429" - integrity sha1-vB0U8DjttzSsRpRKRUVBBpUspCk= - dependencies: - shell-path "^3.0.0" - flat-cache@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" @@ -11260,21 +11276,21 @@ shebang-regex@^3.0.0: resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shell-env@^4.0.0: - version "4.0.1" - resolved "https://registry.npmmirror.com/shell-env/download/shell-env-4.0.1.tgz#883302d9426095d398a39b102a851adb306b8cb8" - integrity sha1-iDMC2UJgldOYo5sQKoUa2zBrjLg= +shell-env@^0.3.0: + version "0.3.0" + resolved "https://registry.npmmirror.com/shell-env/download/shell-env-0.3.0.tgz#2250339022989165bda4eb7bf383afeaaa92dc34" + integrity sha1-IlAzkCKYkWW9pOt784Ov6qqS3DQ= dependencies: - default-shell "^2.0.0" - execa "^5.1.1" - strip-ansi "^7.0.1" + default-shell "^1.0.0" + execa "^0.5.0" + strip-ansi "^3.0.0" -shell-path@^3.0.0: - version "3.0.0" - resolved "https://registry.npmmirror.com/shell-path/download/shell-path-3.0.0.tgz#5c95bc68aade43c06082a0655cb5c97586e4feb0" - integrity sha1-XJW8aKreQ8BggqBlXLXJdYbk/rA= +shell-path@2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/shell-path/download/shell-path-2.1.0.tgz#ea7d06ae1070874a1bac5c65bb9bdd62e4f67a38" + integrity sha1-6n0GrhBwh0obrFxlu5vdYuT2ejg= dependencies: - shell-env "^4.0.0" + shell-env "^0.3.0" shell-quote@^1.6.1: version "1.7.3" @@ -11755,13 +11771,6 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" -strip-ansi@^7.0.1: - version "7.0.1" - resolved "https://registry.npmmirror.com/strip-ansi/download/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" - integrity sha1-YXQKCM42th5Q5lZT8HBg0ACXX7I= - dependencies: - ansi-regex "^6.0.1" - strip-bom@4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878"