diff --git a/package.json b/package.json index b6cde07e4..d1b00bcd2 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "collectCoverage": true, "collectCoverageFrom": [ "src/**/*.js", + "!src/core/*.js", "!src/templates/*.js", "!src/plugins/*.js", "!src/helpers/utils.js", diff --git a/src/core/hooks.js b/src/core/hooks.js new file mode 100644 index 000000000..4dc6eea27 --- /dev/null +++ b/src/core/hooks.js @@ -0,0 +1,141 @@ +import { resolve, join } from 'path' +import { readdirSync } from 'fs' +import { getLocaleCodes } from '../helpers/utils' +import { MODULE_NAME, ROOT_DIR, LOCALE_CODE_KEY, LOCALE_ISO_KEY, LOCALE_DOMAIN_KEY, LOCALE_FILE_KEY, STRATEGIES, COMPONENT_OPTIONS_KEY } from '../helpers/constants' + +export function buildHook (moduleContainer, options) { + const nuxtOptions = moduleContainer.options + + let defaultLangFile + let hasNonDefaultLangFiles = false + + // Copy lang files to the build directory. + if (options.langDir) { + if (!options.locales.length || typeof options.locales[0] === 'string') { + console.error('[' + MODULE_NAME + '] When using "langDir" option, the "locales" option must be a list of objects') + } + + const uniqueFiles = new Set(options.locales.map(locale => locale.file)) + + if (options.defaultLocale) { + const defaultLocaleObject = options.locales.find(locale => locale.code === options.defaultLocale) + if (defaultLocaleObject) { + if (defaultLocaleObject.file) { + defaultLangFile = defaultLocaleObject.file + } else { + console.error(`[${MODULE_NAME}] Default locale is missing the "file" property (required when using "langDir" option)`) + } + } else { + console.error(`[${MODULE_NAME}] Default locale is set to "${options.defaultLocale}" but no locale with that "code" was found`) + } + } + + for (const file of uniqueFiles) { + const isUsingDefaultLangFile = file === defaultLangFile + moduleContainer.addTemplate({ + src: resolve(nuxtOptions.srcDir, options.langDir, file), + fileName: join(ROOT_DIR, (isUsingDefaultLangFile ? 'default-lang' : 'langs'), file) + }) + if (!isUsingDefaultLangFile) { + hasNonDefaultLangFiles = true + } + } + } + + const localeCodes = getLocaleCodes(options.locales) + const { trailingSlash } = nuxtOptions.router + + const templatesOptions = { + ...options, + IS_UNIVERSAL_MODE: nuxtOptions.mode === 'universal', + MODULE_NAME, + LOCALE_CODE_KEY, + LOCALE_ISO_KEY, + LOCALE_DOMAIN_KEY, + LOCALE_FILE_KEY, + STRATEGIES, + COMPONENT_OPTIONS_KEY, + defaultLangFile, + hasNonDefaultLangFiles, + localeCodes, + trailingSlash + } + + const pagesDir = nuxtOptions.dir && nuxtOptions.dir.pages ? nuxtOptions.dir.pages : 'pages' + + if (options.strategy !== STRATEGIES.NO_PREFIX) { + if (localeCodes.length) { + let includeUprefixedFallback = nuxtOptions.target === 'static' + // Doesn't seem like we can tell whether we are in nuxt generate from the module so we'll + // take advantage of the 'generate:before' hook to store variable. + moduleContainer.nuxt.hook('generate:before', () => { includeUprefixedFallback = true }) + const extendRoutes = async routes => { + // This import (or more specifically 'vue-template-compiler' in helpers/components.js) needs to + // be required only at build time to avoid problems when 'vue-template-compiler' dependency is + // not available (at runtime, when using nuxt-start). + const { makeRoutes } = await import('../helpers/routes') + + const localizedRoutes = makeRoutes(routes, { + ...options, + pagesDir, + includeUprefixedFallback, + trailingSlash + }) + routes.splice(0, routes.length) + routes.unshift(...localizedRoutes) + } + + moduleContainer.extendRoutes(extendRoutes) + } + } else if (options.differentDomains) { + // eslint-disable-next-line no-console + console.warn('[' + MODULE_NAME + '] The `differentDomains` option and `no_prefix` strategy are not compatible. Change strategy or disable `differentDomains` option.') + } + + if ('forwardedHost' in options) { + // eslint-disable-next-line no-console + console.warn('[' + MODULE_NAME + '] The `forwardedHost` option is deprecated. You can safely remove it. See: https://github.com/nuxt-community/i18n-module/pull/630.') + } + + const templatesPath = join(__dirname, '..', '/templates') + + // Templates (including plugins) + for (const file of readdirSync(templatesPath)) { + if (file.startsWith('plugin.')) { + if (file === 'plugin.seo.js' && !options.seo) { + continue + } + + moduleContainer.addPlugin({ + src: resolve(templatesPath, file), + fileName: join(ROOT_DIR, file), + options: templatesOptions + }) + } else { + moduleContainer.addTemplate({ + src: resolve(templatesPath, file), + fileName: join(ROOT_DIR, file), + options: templatesOptions + }) + } + } + + // Add vue-i18n-loader if applicable + if (options.vueI18nLoader) { + moduleContainer.extendBuild(config => { + const loaders = config.module.rules.find(el => el.loader === 'vue-loader').options.loaders + if (loaders) { + // vue-loader under 15.0.0 + /* istanbul ignore next */ + loaders.i18n = '@intlify/vue-i18n-loader' + } else { + // vue-loader after 15.0.0 + config.module.rules.push({ + resourceQuery: /blockType=i18n/, + type: 'javascript/auto', + loader: '@intlify/vue-i18n-loader' + }) + } + }) + } +} diff --git a/src/index.js b/src/index.js index 07a2a04a1..e3e462f22 100644 --- a/src/index.js +++ b/src/index.js @@ -1,23 +1,6 @@ -const { resolve, join } = require('path') -const { readdirSync } = require('fs') -const { directive: i18nExtensionsDirective } = require('@intlify/vue-i18n-extensions') - -const { - MODULE_NAME, - ROOT_DIR, - DEFAULT_OPTIONS, - NESTED_OPTIONS, - LOCALE_CODE_KEY, - LOCALE_ISO_KEY, - LOCALE_DOMAIN_KEY, - LOCALE_FILE_KEY, - STRATEGIES, - COMPONENT_OPTIONS_KEY -} = require('./helpers/constants') - -const { - getLocaleCodes -} = require('./helpers/utils') +import { directive as i18nExtensionsDirective } from '@intlify/vue-i18n-extensions' +import { MODULE_NAME, DEFAULT_OPTIONS, NESTED_OPTIONS, STRATEGIES } from './helpers/constants' +import { buildHook } from './core/hooks' module.exports = function (userOptions) { const options = { ...DEFAULT_OPTIONS, ...userOptions, ...this.options.i18n } @@ -35,144 +18,7 @@ module.exports = function (userOptions) { return } - let defaultLangFile - let hasNonDefaultLangFiles = false - - // Copy lang files to the build directory. - if (options.langDir) { - if (!options.locales.length || typeof options.locales[0] === 'string') { - console.error('[' + MODULE_NAME + '] When using "langDir" option, the "locales" option must be a list of objects') - } - - const uniqueFiles = new Set(options.locales.map(locale => locale.file)) - - if (options.defaultLocale) { - const defaultLocaleObject = options.locales.find(locale => locale.code === options.defaultLocale) - if (defaultLocaleObject) { - if (defaultLocaleObject.file) { - defaultLangFile = defaultLocaleObject.file - } else { - console.error(`[${MODULE_NAME}] Default locale is missing the "file" property (required when using "langDir" option)`) - } - } else { - console.error(`[${MODULE_NAME}] Default locale is set to "${options.defaultLocale}" but no locale with that "code" was found`) - } - } - - for (const file of uniqueFiles) { - const isUsingDefaultLangFile = file === defaultLangFile - this.addTemplate({ - src: resolve(this.options.srcDir, options.langDir, file), - fileName: join(ROOT_DIR, (isUsingDefaultLangFile ? 'default-lang' : 'langs'), file) - }) - if (!isUsingDefaultLangFile) { - hasNonDefaultLangFiles = true - } - } - } - - const localeCodes = getLocaleCodes(options.locales) - const { trailingSlash } = this.options.router - - const templatesOptions = { - ...options, - IS_UNIVERSAL_MODE: this.options.mode === 'universal', - MODULE_NAME, - LOCALE_CODE_KEY, - LOCALE_ISO_KEY, - LOCALE_DOMAIN_KEY, - LOCALE_FILE_KEY, - STRATEGIES, - COMPONENT_OPTIONS_KEY, - defaultLangFile, - hasNonDefaultLangFiles, - localeCodes, - trailingSlash - } - - const pagesDir = this.options.dir && this.options.dir.pages ? this.options.dir.pages : 'pages' - - if (options.strategy !== STRATEGIES.NO_PREFIX) { - if (localeCodes.length) { - let includeUprefixedFallback = this.options.target === 'static' - // Doesn't seem like we can tell whether we are in nuxt generate from the module so we'll - // take advantage of the 'generate:before' hook to store variable. - this.nuxt.hook('generate:before', () => { includeUprefixedFallback = true }) - const extendRoutes = routes => { - // This import (or more specifically 'vue-template-compiler' in helpers/components.js) needs to - // be required only at build time to avoid problems when 'vue-template-compiler' dependency is - // not available (at runtime, when using nuxt-start). - const { makeRoutes } = require('./helpers/routes') - - const localizedRoutes = makeRoutes(routes, { - ...options, - pagesDir, - includeUprefixedFallback, - trailingSlash - }) - routes.splice(0, routes.length) - routes.unshift(...localizedRoutes) - } - - this.extendRoutes(extendRoutes) - } - } else if (options.differentDomains) { - // eslint-disable-next-line no-console - console.warn('[' + MODULE_NAME + '] The `differentDomains` option and `no_prefix` strategy are not compatible. Change strategy or disable `differentDomains` option.') - } - - if ('forwardedHost' in options) { - // eslint-disable-next-line no-console - console.warn('[' + MODULE_NAME + '] The `forwardedHost` option is deprecated. You can safely remove it. See: https://github.com/nuxt-community/i18n-module/pull/630.') - } - - const templatesPath = join(__dirname, '/templates') - - // Templates (including plugins) - for (const file of readdirSync(templatesPath)) { - if (file.startsWith('plugin.')) { - if (file === 'plugin.seo.js' && !options.seo) { - continue - } - - this.addPlugin({ - src: resolve(templatesPath, file), - fileName: join(ROOT_DIR, file), - options: templatesOptions - }) - } else { - this.addTemplate({ - src: resolve(templatesPath, file), - fileName: join(ROOT_DIR, file), - options: templatesOptions - }) - } - } - - // Add vue-i18n to vendors if using Nuxt 1.x - if (this.options.build.vendor) { - /* istanbul ignore next */ - this.options.build.vendor.push('vue-i18n') - } - - // Add vue-i18n-loader if applicable - if (options.vueI18nLoader) { - this.extendBuild(config => { - const loaders = config.module.rules.find(el => el.loader === 'vue-loader').options.loaders - if (loaders) { - // vue-loader under 15.0.0 - /* istanbul ignore next */ - loaders.i18n = '@intlify/vue-i18n-loader' - } else { - // vue-loader after 15.0.0 - config.module.rules.push({ - resourceQuery: /blockType=i18n/, - type: 'javascript/auto', - loader: '@intlify/vue-i18n-loader' - }) - } - }) - } + this.nuxt.hook('build:before', () => buildHook(this, options)) this.options.router.middleware.push('nuxti18n') this.options.render.bundleRenderer.directives = this.options.render.bundleRenderer.directives || {}