From a66dabb6132811b9e300b0b25191de744e2c2f30 Mon Sep 17 00:00:00 2001 From: Guillaume Chau Date: Sun, 29 Apr 2018 23:05:48 +0200 Subject: [PATCH] feat(ui): plugin locales --- docs/plugin-dev-ui.md | 48 ++++++++++++++++++- .../@vue/cli-plugin-eslint/locales/en.json | 13 +++++ .../@vue/cli-plugin-eslint/locales/fr.json | 13 +++++ packages/@vue/cli-plugin-eslint/ui.js | 20 ++++---- packages/@vue/cli-service/locales/en.json | 18 +++++++ packages/@vue/cli-service/locales/fr.json | 18 +++++++ packages/@vue/cli-service/ui.js | 8 ++-- .../src/components/AssetList.vue | 4 +- .../src/components/AssetListItem.vue | 2 +- .../src/components/BuildStatus.vue | 34 +++++++++---- .../src/components/ModuleList.vue | 4 +- .../src/components/SpeedStats.vue | 4 +- .../src/components/WebpackAnalyzer.vue | 27 ++++++----- .../src/components/WebpackDashboard.vue | 12 ++--- .../cli-ui-addon-webpack/src/locales/en.json | 45 +++++++++++++++++ .../cli-ui-addon-webpack/src/locales/fr.json | 45 +++++++++++++++++ .../@vue/cli-ui-addon-webpack/src/main.js | 7 +++ .../src/mixins/Dashboard.js | 4 -- packages/@vue/cli-ui/package.json | 1 + packages/@vue/cli-ui/src/App.vue | 1 + .../src/components/ClientAddonLoader.vue | 7 +-- .../src/components/ConfigurationItem.vue | 4 +- .../cli-ui/src/components/LocaleLoader.vue | 38 +++++++++++++++ .../@vue/cli-ui/src/components/NavList.vue | 2 +- .../cli-ui/src/components/PromptCheckbox.vue | 6 +-- .../cli-ui/src/components/PromptConfirm.vue | 4 +- .../cli-ui/src/components/PromptError.vue | 2 +- .../cli-ui/src/components/PromptInput.vue | 4 +- .../@vue/cli-ui/src/components/PromptList.vue | 6 +-- .../@vue/cli-ui/src/graphql-api/channels.js | 3 +- .../graphql-api/connectors/client-addons.js | 4 +- .../src/graphql-api/connectors/locales.js | 26 ++++++++++ .../src/graphql-api/connectors/plugins.js | 22 +++++++-- .../src/graphql-api/connectors/projects.js | 3 ++ .../@vue/cli-ui/src/graphql-api/resolvers.js | 7 ++- .../@vue/cli-ui/src/graphql-api/type-defs.js | 7 +++ .../utils/{serve.js => resolve-path.js} | 2 +- .../@vue/cli-ui/src/graphql/localeAdded.gql | 7 +++ .../cli-ui/src/graphql/localeFragment.gql | 4 ++ packages/@vue/cli-ui/src/graphql/locales.gql | 7 +++ packages/@vue/cli-ui/src/i18n.js | 6 +++ packages/@vue/cli-ui/src/locales/fr.json | 16 ++++++- .../@vue/cli-ui/src/util/ClientAddonApi.js | 15 +++++- .../cli-ui/src/views/ProjectTaskDetails.vue | 4 +- 44 files changed, 451 insertions(+), 83 deletions(-) create mode 100644 packages/@vue/cli-plugin-eslint/locales/en.json create mode 100644 packages/@vue/cli-plugin-eslint/locales/fr.json create mode 100644 packages/@vue/cli-service/locales/en.json create mode 100644 packages/@vue/cli-service/locales/fr.json create mode 100644 packages/@vue/cli-ui-addon-webpack/src/locales/en.json create mode 100644 packages/@vue/cli-ui-addon-webpack/src/locales/fr.json create mode 100644 packages/@vue/cli-ui/src/components/LocaleLoader.vue create mode 100644 packages/@vue/cli-ui/src/graphql-api/connectors/locales.js rename packages/@vue/cli-ui/src/graphql-api/utils/{serve.js => resolve-path.js} (82%) create mode 100644 packages/@vue/cli-ui/src/graphql/localeAdded.gql create mode 100644 packages/@vue/cli-ui/src/graphql/localeFragment.gql create mode 100644 packages/@vue/cli-ui/src/graphql/locales.gql diff --git a/docs/plugin-dev-ui.md b/docs/plugin-dev-ui.md index b6d24cf8f..3ec674cff 100644 --- a/docs/plugin-dev-ui.md +++ b/docs/plugin-dev-ui.md @@ -10,6 +10,7 @@ This guide will walk you through the development of cli-ui specific features for - [Shared data](#shared-data) - [Plugin actions](#plugin-actions) - [Inter-process communication (IPC)](#inter-process-communication-ipc) +- [Localization](#localization) - [Hooks](#hooks) - [Public static files](#public-static-files) @@ -350,11 +351,19 @@ ClientAddonApi.component('vue-webpack-dashboard', WebpackDashboard) ClientAddonApi.addRoutes('vue-webpack', [ { path: '', name: 'test-webpack-route', component: TestView } ]) + +// You can translate your plugin components +// Load the locale files (uses vue-i18n) +const locales = require.context('./locales', true, /[a-z0-9]+\.json$/i) +locales.keys().forEach(key => { + const locale = key.match(/([a-z0-9]+)\./i)[1] + ClientAddonApi.addLocalization(locale, locales(key)) +}) ``` The cli-ui registers `Vue` and `ClientAddonApi` as global variables in the `window` scope. -In your components, you can use all the components and the CSS classes of [@vue/ui](https://github.com/vuejs/ui) and [@vue/cli-ui](https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-ui/src/components) in order to keep the look and feel consistent. +In your components, you can use all the components and the CSS classes of [@vue/ui](https://github.com/vuejs/ui) and [@vue/cli-ui](https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-ui/src/components) in order to keep the look and feel consistent. You can also translate the strings with [vue-i18n](https://github.com/kazupon/vue-i18n) which is included. #### Register the client addon Back to the `ui.js` file, use the `api.addClientAddon` method with a require query to the built folder: @@ -632,6 +641,43 @@ api.ipcSend({ }) ``` +### Localization + +You can put locale files compatible with [vue-i18n](https://github.com/kazupon/vue-i18n) in a `locales` folder at the root of your plugin. They will be automatically loaded into the client when the project is opened. You can then use `$t` to translate strings in your components and other vue-i18n helpers. Also, the strings used in the UI API (like `describeTask`) will go through vue-i18n as well to you can localize them. + +Example `locales` folder: + +``` +vue-cli-plugin/locales/en.json +vue-cli-plugin/locales/fr.json +``` + +Example usage in API: + +```js +api.describeConfig({ + // vue-i18n path + description: 'my-plugin.config.foo' +}) +``` + +Example usage in components: + +```html +{{ $t('my-plugin.actions.bar') }} +``` + +You can also load the locale files in a client addon if you prefer, using the `ClientAddonApi`: + +```js +// Load the locale files (uses vue-i18n) +const locales = require.context('./locales', true, /[a-z0-9]+\.json$/i) +locales.keys().forEach(key => { + const locale = key.match(/([a-z0-9]+)\./i)[1] + ClientAddonApi.addLocalization(locale, locales(key)) +}) +``` + ### Hooks Hooks allows to react to certain cli-ui events. diff --git a/packages/@vue/cli-plugin-eslint/locales/en.json b/packages/@vue/cli-plugin-eslint/locales/en.json new file mode 100644 index 000000000..4617b1589 --- /dev/null +++ b/packages/@vue/cli-plugin-eslint/locales/en.json @@ -0,0 +1,13 @@ +{ + "eslint": { + "config": { + "eslint": { + "description": "Error checking & Code quality", + "groups": { + "strongly-recommended": "Strongly recommended", + "recommended": "Recommended" + } + } + } + } +} diff --git a/packages/@vue/cli-plugin-eslint/locales/fr.json b/packages/@vue/cli-plugin-eslint/locales/fr.json new file mode 100644 index 000000000..9a7324006 --- /dev/null +++ b/packages/@vue/cli-plugin-eslint/locales/fr.json @@ -0,0 +1,13 @@ +{ + "eslint": { + "config": { + "eslint": { + "description": "Vérification des erreurs & Qualité du code", + "groups": { + "strongly-recommended": "Fortement recommandé", + "recommended": "Recommandé" + } + } + } + } +} diff --git a/packages/@vue/cli-plugin-eslint/ui.js b/packages/@vue/cli-plugin-eslint/ui.js index 0027c5f21..d3f449054 100644 --- a/packages/@vue/cli-plugin-eslint/ui.js +++ b/packages/@vue/cli-plugin-eslint/ui.js @@ -5,7 +5,7 @@ module.exports = api => { api.describeConfig({ id: 'eslintrc', name: 'ESLint configuration', - description: 'Error checking & Code quality', + description: 'eslint.config.eslint.description', link: 'https://eslint.org', icon: '.eslintrc.json', files: { @@ -19,7 +19,7 @@ module.exports = api => { name: 'vue/attribute-hyphenation', type: 'list', message: 'Attribute hyphenation', - group: 'Strongly recommended', + group: 'eslint.config.eslint.groups.strongly-recommended', description: 'Enforce attribute naming style in template (`my-prop` or `myProp`)', link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/attribute-hyphenation.md', default: JSON.stringify('off'), @@ -43,7 +43,7 @@ module.exports = api => { name: 'vue/html-end-tags', type: 'confirm', message: 'Template end tags style', - group: 'Strongly recommended', + group: 'eslint.config.eslint.groups.strongly-recommended', description: 'End tag on Void elements, end tags and self-closing opening tags', link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/html-end-tags.md', default: false, @@ -55,7 +55,7 @@ module.exports = api => { name: 'vue/html-indent', type: 'list', message: 'Template indentation', - group: 'Strongly recommended', + group: 'eslint.config.eslint.groups.strongly-recommended', description: 'Enforce indentation in template', link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/html-indent.md', default: JSON.stringify('off'), @@ -87,7 +87,7 @@ module.exports = api => { name: 'vue/html-self-closing', type: 'confirm', message: 'Template tag self-closing style', - group: 'Strongly recommended', + group: 'eslint.config.eslint.groups.strongly-recommended', description: 'Self-close any component or non-Void element tags', link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/html-self-closing.md', default: false, @@ -99,7 +99,7 @@ module.exports = api => { name: 'vue/require-default-prop', type: 'confirm', message: 'Require default in required props', - group: 'Strongly recommended', + group: 'eslint.config.eslint.groups.strongly-recommended', description: 'This rule requires default value to be set for each props that are not marked as `required`', link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/require-default-prop.md', default: false, @@ -111,7 +111,7 @@ module.exports = api => { name: 'vue/require-prop-types', type: 'confirm', message: 'Require types for props', - group: 'Strongly recommended', + group: 'eslint.config.eslint.groups.strongly-recommended', description: 'In committed code, prop definitions should always be as detailed as possible, specifying at least type(s)', link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/require-prop-types.md', default: false, @@ -123,7 +123,7 @@ module.exports = api => { name: 'vue/attributes-order', type: 'confirm', message: 'Attribute order', - group: 'Recommended', + group: 'eslint.config.eslint.groups.recommended', description: 'This rule aims to enforce ordering of component attributes (the default order is specified in the Vue style guide)', link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/attributes-order.md', default: false, @@ -135,7 +135,7 @@ module.exports = api => { name: 'vue/html-quotes', type: 'list', message: 'Attribute quote style', - group: 'Recommended', + group: 'eslint.config.eslint.groups.recommended', description: 'Enforce style of the attribute quotes in templates', link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/html-quotes.md', default: JSON.stringify('off'), @@ -159,7 +159,7 @@ module.exports = api => { name: 'vue/order-in-components', type: 'confirm', message: 'Component options order', - group: 'Recommended', + group: 'eslint.config.eslint.groups.recommended', description: 'This rule aims to enforce ordering of component options (the default order is specified in the Vue style guide)', link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/order-in-components.md', default: false, diff --git a/packages/@vue/cli-service/locales/en.json b/packages/@vue/cli-service/locales/en.json new file mode 100644 index 000000000..5cf420df5 --- /dev/null +++ b/packages/@vue/cli-service/locales/en.json @@ -0,0 +1,18 @@ +{ + "vue-webpack": { + "dashboard": { + "title": "Dashboard" + }, + "analyzer": { + "title": "Analyzer" + }, + "tasks": { + "serve": { + "description": "Compiles and hot-reloads for development" + }, + "build": { + "description": "Compiles and minifies for production" + } + } + } +} diff --git a/packages/@vue/cli-service/locales/fr.json b/packages/@vue/cli-service/locales/fr.json new file mode 100644 index 000000000..98abd2c3b --- /dev/null +++ b/packages/@vue/cli-service/locales/fr.json @@ -0,0 +1,18 @@ +{ + "vue-webpack": { + "dashboard": { + "title": "Tableau de bord" + }, + "analyzer": { + "title": "Analyseur" + }, + "tasks": { + "serve": { + "description": "Compile et recharge à chaud pour le développement" + }, + "build": { + "description": "Compile et minifie pour la production" + } + } + } +} diff --git a/packages/@vue/cli-service/ui.js b/packages/@vue/cli-service/ui.js index 41d923e7e..1eb9d7ef2 100644 --- a/packages/@vue/cli-service/ui.js +++ b/packages/@vue/cli-service/ui.js @@ -34,13 +34,13 @@ module.exports = api => { views: [ { id: 'vue-webpack-dashboard', - label: 'Dashboard', + label: 'vue-webpack.dashboard.title', icon: 'dashboard', component: 'vue-webpack-dashboard' }, { id: 'vue-webpack-analyzer', - label: 'Analyzer', + label: 'vue-webpack.analyzer.title', icon: 'donut_large', component: 'vue-webpack-analyzer' } @@ -49,7 +49,7 @@ module.exports = api => { } api.describeTask({ match: /vue-cli-service serve/, - description: 'Compiles and hot-reloads for development', + description: 'vue-webpack.tasks.serve.description', link: 'https://github.com/vuejs/vue-cli/blob/dev/docs/cli-service.md#serve', prompts: [ { @@ -121,7 +121,7 @@ module.exports = api => { }) api.describeTask({ match: /vue-cli-service build/, - description: 'Compiles and minifies for production', + description: 'vue-webpack.tasks.build.description', link: 'https://github.com/vuejs/vue-cli/blob/dev/docs/cli-service.md#build', prompts: [ { diff --git a/packages/@vue/cli-ui-addon-webpack/src/components/AssetList.vue b/packages/@vue/cli-ui-addon-webpack/src/components/AssetList.vue index 09fd399df..45f75394c 100644 --- a/packages/@vue/cli-ui-addon-webpack/src/components/AssetList.vue +++ b/packages/@vue/cli-ui-addon-webpack/src/components/AssetList.vue @@ -1,7 +1,9 @@ diff --git a/packages/@vue/cli-ui/src/components/PromptInput.vue b/packages/@vue/cli-ui/src/components/PromptInput.vue index bd0cfbde4..1b9519d07 100644 --- a/packages/@vue/cli-ui/src/components/PromptInput.vue +++ b/packages/@vue/cli-ui/src/components/PromptInput.vue @@ -5,8 +5,8 @@ >
diff --git a/packages/@vue/cli-ui/src/components/PromptList.vue b/packages/@vue/cli-ui/src/components/PromptList.vue index edc877b56..c86a5cc97 100644 --- a/packages/@vue/cli-ui/src/components/PromptList.vue +++ b/packages/@vue/cli-ui/src/components/PromptList.vue @@ -5,8 +5,8 @@ >
@@ -37,7 +37,7 @@ export default { methods: { generateLabel (choice) { - let label = choice.name + let label = this.$t(choice.name) if (choice.isDefault) { label += ` (${this.$t('components.prompt-list.default')})` } diff --git a/packages/@vue/cli-ui/src/graphql-api/channels.js b/packages/@vue/cli-ui/src/graphql-api/channels.js index 7459900b6..c8ed274f6 100644 --- a/packages/@vue/cli-ui/src/graphql-api/channels.js +++ b/packages/@vue/cli-ui/src/graphql-api/channels.js @@ -11,5 +11,6 @@ module.exports = { CLIENT_ADDON_ADDED: 'client_addon_added', SHARED_DATA_UPDATED: 'shared_data_updated', PLUGIN_ACTION_CALLED: 'plugin_action_called', - PLUGIN_ACTION_RESOLVED: 'plugin_action_resolved' + PLUGIN_ACTION_RESOLVED: 'plugin_action_resolved', + LOCALE_ADDED: 'locale_added' } diff --git a/packages/@vue/cli-ui/src/graphql-api/connectors/client-addons.js b/packages/@vue/cli-ui/src/graphql-api/connectors/client-addons.js index 1bd705fb6..f6b16ad2b 100644 --- a/packages/@vue/cli-ui/src/graphql-api/connectors/client-addons.js +++ b/packages/@vue/cli-ui/src/graphql-api/connectors/client-addons.js @@ -2,7 +2,7 @@ const path = require('path') // Subs const channels = require('../channels') // Utils -const { getBasePath } = require('../utils/serve') +const { resolveModuleRoot } = require('../utils/resolve-path') let addons = [] @@ -43,7 +43,7 @@ function serve (req, res) { const { id, 0: file } = req.params const addon = findOne(id) if (addon && addon.path) { - const basePath = getBasePath(require.resolve(addon.path)) + const basePath = resolveModuleRoot(require.resolve(addon.path)) if (basePath) { res.sendFile(path.join(basePath, file)) return diff --git a/packages/@vue/cli-ui/src/graphql-api/connectors/locales.js b/packages/@vue/cli-ui/src/graphql-api/connectors/locales.js new file mode 100644 index 000000000..4630e9f0d --- /dev/null +++ b/packages/@vue/cli-ui/src/graphql-api/connectors/locales.js @@ -0,0 +1,26 @@ +// Subs +const channels = require('../channels') + +let locales = [] + +function list (context) { + return locales +} + +function add ({ lang, strings }, context) { + const locale = { lang, strings } + locales.push(locale) + context.pubsub.publish(channels.LOCALE_ADDED, { + localeAdded: locale + }) +} + +function clear (context) { + locales = [] +} + +module.exports = { + list, + add, + clear +} diff --git a/packages/@vue/cli-ui/src/graphql-api/connectors/plugins.js b/packages/@vue/cli-ui/src/graphql-api/connectors/plugins.js index dceec6875..abf418bd8 100644 --- a/packages/@vue/cli-ui/src/graphql-api/connectors/plugins.js +++ b/packages/@vue/cli-ui/src/graphql-api/connectors/plugins.js @@ -17,6 +17,7 @@ const { } = require('@vue/cli/lib/util/installDeps') const invoke = require('@vue/cli/lib/invoke') const notifier = require('node-notifier') +const globby = require('globby') // Subs const channels = require('../channels') // Connectors @@ -27,11 +28,12 @@ const progress = require('./progress') const logs = require('./logs') const clientAddons = require('./client-addons') const views = require('./views') +const locales = require('./locales') // Api const PluginApi = require('../api/PluginApi') // Utils const { getCommand } = require('../utils/command') -const { getBasePath } = require('../utils/serve') +const { resolveModuleRoot } = require('../utils/resolve-path') const ipc = require('../utils/ipc') const PROGRESS_ID = 'plugin-installation' @@ -54,7 +56,7 @@ let installationStep let projectId function getPath (id) { - return path.dirname(resolveModule(id, cwd.get())) + return resolveModuleRoot(resolveModule(id, cwd.get()), id) } function findPlugins (deps) { @@ -91,7 +93,7 @@ function resetPluginApi (context) { // Run Plugin API runPluginApi('@vue/cli-service', context) plugins.forEach(plugin => runPluginApi(plugin.id, context)) - runPluginApi('.', context, 'vue-cli-ui') + runPluginApi(cwd.get(), context, 'vue-cli-ui') // Add client addons pluginApi.clientAddons.forEach(options => clientAddons.add(options, context)) // Add views @@ -121,6 +123,18 @@ function runPluginApi (id, context, fileName = 'ui') { module(pluginApi) pluginApi.pluginId = null } + + // Locales + try { + const folder = fs.existsSync(id) ? id : getPath(id) + const paths = globby.sync([path.join(folder, './locales/*.json')]) + paths.forEach(file => { + const basename = path.basename(file) + const lang = basename.substr(0, basename.indexOf('.')) + const strings = JSON.parse(fs.readFileSync(file, { encoding: 'utf8' })) + locales.add({ lang, strings }, context) + }) + } catch (e) {} } function findOne (id, context) { @@ -367,7 +381,7 @@ async function callAction ({ id, params }, context) { function serve (req, res) { const { id, 0: file } = req.params - const basePath = getBasePath(require.resolve(id), id) + const basePath = id === '.' ? cwd.get() : getPath(id) if (basePath) { res.sendFile(path.join(basePath, 'ui-public', file)) return diff --git a/packages/@vue/cli-ui/src/graphql-api/connectors/projects.js b/packages/@vue/cli-ui/src/graphql-api/connectors/projects.js index 662a28b03..f8e79daa4 100644 --- a/packages/@vue/cli-ui/src/graphql-api/connectors/projects.js +++ b/packages/@vue/cli-ui/src/graphql-api/connectors/projects.js @@ -14,6 +14,7 @@ const cwd = require('./cwd') const prompts = require('./prompts') const folders = require('./folders') const plugins = require('./plugins') +const locales = require('./locales') // Context const getContext = require('../context') @@ -316,6 +317,8 @@ async function open (id, context) { lastProject = currentProject currentProject = project cwd.set(project.path, context) + // Reset locales + locales.clear() // Load plugins plugins.list(project.path, context) diff --git a/packages/@vue/cli-ui/src/graphql-api/resolvers.js b/packages/@vue/cli-ui/src/graphql-api/resolvers.js index 73d3e7c07..327ef8d62 100644 --- a/packages/@vue/cli-ui/src/graphql-api/resolvers.js +++ b/packages/@vue/cli-ui/src/graphql-api/resolvers.js @@ -12,6 +12,7 @@ const progress = require('./connectors/progress') const files = require('./connectors/files') const clientAddons = require('./connectors/client-addons') const sharedData = require('./connectors/shared-data') +const locales = require('./connectors/locales') // Start ipc server require('./utils/ipc') @@ -37,7 +38,8 @@ const resolvers = [{ cwd: () => cwd.get(), progress: (root, { id }, context) => progress.get(id, context), clientAddons: (root, args, context) => clientAddons.list(context), - sharedData: (root, { id }, context) => sharedData.get(id, context) + sharedData: (root, { id }, context) => sharedData.get(id, context), + locales: (root, args, context) => locales.list(context) }, Mutation: { @@ -73,6 +75,9 @@ const resolvers = [{ (parent, args, { pubsub }) => pubsub.asyncIterator(channels.SHARED_DATA_UPDATED), (payload, vars) => payload.sharedDataUpdated.id === vars.id ) + }, + localeAdded: { + subscribe: (parent, args, { pubsub }) => pubsub.asyncIterator(channels.LOCALE_ADDED) } } }] diff --git a/packages/@vue/cli-ui/src/graphql-api/type-defs.js b/packages/@vue/cli-ui/src/graphql-api/type-defs.js index 091260711..f0d004b20 100644 --- a/packages/@vue/cli-ui/src/graphql-api/type-defs.js +++ b/packages/@vue/cli-ui/src/graphql-api/type-defs.js @@ -54,11 +54,17 @@ type SharedData { value: JSON } +type Locale { + lang: String! + strings: JSON! +} + type Query { progress (id: ID!): Progress cwd: String! clientAddons: [ClientAddon] sharedData (id: ID!): SharedData + locales: [Locale] } type Mutation { @@ -72,6 +78,7 @@ type Subscription { cwdChanged: String! clientAddonAdded: ClientAddon sharedDataUpdated (id: ID!): SharedData + localeAdded: Locale } `] diff --git a/packages/@vue/cli-ui/src/graphql-api/utils/serve.js b/packages/@vue/cli-ui/src/graphql-api/utils/resolve-path.js similarity index 82% rename from packages/@vue/cli-ui/src/graphql-api/utils/serve.js rename to packages/@vue/cli-ui/src/graphql-api/utils/resolve-path.js index 91554fa80..d579d22ae 100644 --- a/packages/@vue/cli-ui/src/graphql-api/utils/serve.js +++ b/packages/@vue/cli-ui/src/graphql-api/utils/resolve-path.js @@ -1,4 +1,4 @@ -exports.getBasePath = function (filePath, id = null) { +exports.resolveModuleRoot = function (filePath, id = null) { { const index = filePath.lastIndexOf('/index.js') if (index !== -1) { diff --git a/packages/@vue/cli-ui/src/graphql/localeAdded.gql b/packages/@vue/cli-ui/src/graphql/localeAdded.gql new file mode 100644 index 000000000..988b0907d --- /dev/null +++ b/packages/@vue/cli-ui/src/graphql/localeAdded.gql @@ -0,0 +1,7 @@ +#import "./localeFragment.gql" + +subscription localeAdded { + localeAdded { + ...locale + } +} diff --git a/packages/@vue/cli-ui/src/graphql/localeFragment.gql b/packages/@vue/cli-ui/src/graphql/localeFragment.gql new file mode 100644 index 000000000..ecf506ad4 --- /dev/null +++ b/packages/@vue/cli-ui/src/graphql/localeFragment.gql @@ -0,0 +1,4 @@ +fragment locale on Locale { + lang + strings +} diff --git a/packages/@vue/cli-ui/src/graphql/locales.gql b/packages/@vue/cli-ui/src/graphql/locales.gql new file mode 100644 index 000000000..a5fed39b5 --- /dev/null +++ b/packages/@vue/cli-ui/src/graphql/locales.gql @@ -0,0 +1,7 @@ +#import "./localeFragment.gql" + +query locales { + locales { + ...locale + } +} diff --git a/packages/@vue/cli-ui/src/i18n.js b/packages/@vue/cli-ui/src/i18n.js index db9e52d3a..8a09e223d 100644 --- a/packages/@vue/cli-ui/src/i18n.js +++ b/packages/@vue/cli-ui/src/i18n.js @@ -1,5 +1,6 @@ import Vue from 'vue' import VueI18n from 'vue-i18n' +import deepmerge from 'deepmerge' Vue.use(VueI18n) @@ -30,4 +31,9 @@ const i18n = new VueI18n({ messages: loadLocaleMessages() }) +export function mergeLocale (lang, messages) { + const newData = deepmerge(i18n.getLocaleMessage(lang), messages) + i18n.setLocaleMessage(lang, newData) +} + export default i18n diff --git a/packages/@vue/cli-ui/src/locales/fr.json b/packages/@vue/cli-ui/src/locales/fr.json index 21a012635..30cfb09eb 100644 --- a/packages/@vue/cli-ui/src/locales/fr.json +++ b/packages/@vue/cli-ui/src/locales/fr.json @@ -62,7 +62,8 @@ "tooltips": { "plugins": "Plugins", "configuration": "Configuration", - "tasks": "Tâches" + "tasks": "Tâches", + "more": "Plus" } }, "project-select-list": { @@ -275,6 +276,12 @@ "project-configurations": { "title": "Configuration du projet" }, + "project-configuration-details": { + "actions": { + "cancel": "Annuler les changements", + "save": "Sauvegarder les modifications" + } + }, "project-tasks": { "title": "Tâches du projet" }, @@ -288,6 +295,13 @@ "parameters": "Paramètres", "more-info": "Plus d'infos", "output": "Sortie" + }, + "about": { + "title": "A propos", + "description": "@vue/cli-ui est un paquet inclus dans @vue/cli qui affiche une interface graphique.", + "quote": "Vue-cli 3.x is a complete rewrite, with a lot of new awesome features. You will be to select features like routing, Vuex or Typescript, then add and upgrade building blocks called \"vue-cli plugins\". But having so much more options also means the tool is now more complex and harder to start using. That's why we thought having a full-blown GUI would help discover the new features, search and install vue-cli plugins and unlock more possibilities overall while not being limited by a terminal interface. To sum up, vue-cli will not only allow you to bootstrap a new project easily, but it will also remain useful for ongoing work afterwards!", + "links": "Liens utiles", + "back": "Retour" } } } diff --git a/packages/@vue/cli-ui/src/util/ClientAddonApi.js b/packages/@vue/cli-ui/src/util/ClientAddonApi.js index 1fa656fa1..27a9b37fd 100644 --- a/packages/@vue/cli-ui/src/util/ClientAddonApi.js +++ b/packages/@vue/cli-ui/src/util/ClientAddonApi.js @@ -1,5 +1,6 @@ import Vue from 'vue' import router from '../router' +import { mergeLocale } from '../i18n' import ProjectHome from '../views/ProjectHome.vue' export default class ClientAddonApi { @@ -18,7 +19,7 @@ export default class ClientAddonApi { this.components.set(id, definition) const componentId = toComponentId(id) Vue.component(componentId, definition) - console.log(`Registered ${componentId} component`) + console.log(`[ClientAddonApi] Registered ${componentId} component`) // Call listeners const listeners = this.componentListeners.get(id) if (listeners) { @@ -47,6 +48,18 @@ export default class ClientAddonApi { children: routes } ]) + console.log(`[ClientAddonApi] Registered new routes under the /addon/${id} route`) + } + + /** + * Merge new strings into the specified lang translations (using vue-i18n). + * + * @param {string} lang Locale to merge to (ex: 'en', 'fr'...) + * @param {object} strings A vue-i18n strings object containing the translations + */ + addLocalization (lang, strings) { + mergeLocale(lang, strings) + console.log(`[ClientAddonApi] Registered new strings for locale ${lang}`) } /* Internal */ diff --git a/packages/@vue/cli-ui/src/views/ProjectTaskDetails.vue b/packages/@vue/cli-ui/src/views/ProjectTaskDetails.vue index 5b8e76771..0b2764c05 100644 --- a/packages/@vue/cli-ui/src/views/ProjectTaskDetails.vue +++ b/packages/@vue/cli-ui/src/views/ProjectTaskDetails.vue @@ -4,7 +4,7 @@
{{ task.name }}
-
{{ task.description }}
+
{{ $t(task.description) }}
@@ -66,7 +66,7 @@ :key="view.id" :value="view.id" :icon-left="view.icon" - :label="view.label" + :label="$t(view.label)" />