From 39b917cd43c6441b0f4b857e5d26d482b9dc0d26 Mon Sep 17 00:00:00 2001 From: Harlan Wilton Date: Fri, 20 Sep 2024 17:38:48 +1000 Subject: [PATCH] feat: `nuxt-i18n-micro` module integration (#357) --- package.json | 1 + pnpm-lock.yaml | 42 +++++++++++++++++ src/module.ts | 23 ++++++---- src/runtime/types.ts | 7 +++ test/fixtures/i18n-micro/locales/en.ts | 3 ++ test/fixtures/i18n-micro/locales/hr.ts | 3 ++ test/fixtures/i18n-micro/locales/ja.ts | 3 ++ test/fixtures/i18n-micro/locales/nl.ts | 3 ++ test/fixtures/i18n-micro/locales/zh.ts | 3 ++ test/fixtures/i18n-micro/nuxt.config.ts | 46 +++++++++++++++++++ .../i18n-micro/pages/dynamic/[page].vue | 3 ++ test/fixtures/i18n-micro/pages/index.vue | 14 ++++++ test/fixtures/i18n-micro/pages/test.vue | 5 ++ .../i18n-micro/server/routes/__sitemap.ts | 11 +++++ .../i18n-micro/server/routes/i18n-urls.ts | 21 +++++++++ 15 files changed, 178 insertions(+), 10 deletions(-) create mode 100644 test/fixtures/i18n-micro/locales/en.ts create mode 100644 test/fixtures/i18n-micro/locales/hr.ts create mode 100644 test/fixtures/i18n-micro/locales/ja.ts create mode 100644 test/fixtures/i18n-micro/locales/nl.ts create mode 100644 test/fixtures/i18n-micro/locales/zh.ts create mode 100644 test/fixtures/i18n-micro/nuxt.config.ts create mode 100644 test/fixtures/i18n-micro/pages/dynamic/[page].vue create mode 100644 test/fixtures/i18n-micro/pages/index.vue create mode 100644 test/fixtures/i18n-micro/pages/test.vue create mode 100644 test/fixtures/i18n-micro/server/routes/__sitemap.ts create mode 100644 test/fixtures/i18n-micro/server/routes/i18n-urls.ts diff --git a/package.json b/package.json index 37455391..cdbe12ef 100644 --- a/package.json +++ b/package.json @@ -77,6 +77,7 @@ "eslint-plugin-n": "^17.10.3", "execa": "^9.4.0", "nuxt": "^3.13.2", + "nuxt-i18n-micro": "^1.16.1", "typescript": "5.6.2", "vitest": "^2.1.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 51ad60af..76174abe 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -94,6 +94,9 @@ importers: nuxt: specifier: ^3.13.2 version: 3.13.2(@parcel/watcher@2.4.1)(@types/node@22.5.5)(eslint@9.10.0(jiti@1.21.6))(ioredis@5.4.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.22.0)(terser@5.33.0)(typescript@5.6.2)(vite@5.4.6(@types/node@22.5.5)(terser@5.33.0))(webpack-sources@3.2.3) + nuxt-i18n-micro: + specifier: ^1.16.1 + version: 1.16.1(magicast@0.3.5)(rollup@4.22.0)(vite@5.4.6(@types/node@22.5.5)(terser@5.33.0))(webpack-sources@3.2.3) typescript: specifier: 5.6.2 version: 5.6.2 @@ -2453,6 +2456,9 @@ packages: confbox@0.1.7: resolution: {integrity: sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==} + connected-domain@1.0.0: + resolution: {integrity: sha512-lHlohUiJxlpunvDag2Y0pO20bnvarMjnrdciZeuJUqRwrf/5JHNhdpiPIr5GQ8IkqrFj5TDMQwcCjblGo1oeuA==} + consola@3.2.3: resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==} engines: {node: ^14.18.0 || >=16.10.0} @@ -4115,6 +4121,9 @@ packages: engines: {node: ^16.10.0 || >=18.0.0} hasBin: true + nuxt-i18n-micro@1.16.1: + resolution: {integrity: sha512-zBBNC+/9I5R4a6PipCsDHJYVKuWipO59aLMvkrtV2lCR9gshvQ6fSRL4mwHg+Zj40du17NbOih45tNrSq6xN6g==} + nuxt-site-config-kit@2.2.18: resolution: {integrity: sha512-iPtf2X1fvI9m9VV04edSqNGC2EzQ1aLB7F2/AOxYRktCJxHeTdBGifuNPc90EaEIOfWx+gf3lmRd4EppGoAMSA==} @@ -4568,6 +4577,9 @@ packages: protocols@2.0.1: resolution: {integrity: sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==} + ps-node@0.1.6: + resolution: {integrity: sha512-w7QJhUTbu70hpDso0YXDRNKCPNuchV8UTUZsAv0m7Qj5g85oHOJfr9drA1EjvK4nQK/bG8P97W4L6PJ3IQLoOA==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -5046,6 +5058,9 @@ packages: tabbable@6.2.0: resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + table-parser@0.1.3: + resolution: {integrity: sha512-LCYeuvqqoPII3lzzYaXKbC3Forb+d2u4bNwhk/9FlivuGRxPE28YEWAYcujeSlLLDlMfvy29+WPybFJZFiKMYg==} + tailwind-config-viewer@2.0.4: resolution: {integrity: sha512-icvcmdMmt9dphvas8wL40qttrHwAnW3QEN4ExJ2zICjwRsPj7gowd1cOceaWG3IfTuM/cTNGQcx+bsjMtmV+cw==} engines: {node: '>=13'} @@ -8647,6 +8662,8 @@ snapshots: confbox@0.1.7: {} + connected-domain@1.0.0: {} + consola@3.2.3: {} console-control-strings@1.1.0: {} @@ -10736,6 +10753,23 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + nuxt-i18n-micro@1.16.1(magicast@0.3.5)(rollup@4.22.0)(vite@5.4.6(@types/node@22.5.5)(terser@5.33.0))(webpack-sources@3.2.3): + dependencies: + '@nuxt/devtools-kit': 1.4.2(magicast@0.3.5)(rollup@4.22.0)(vite@5.4.6(@types/node@22.5.5)(terser@5.33.0))(webpack-sources@3.2.3) + '@nuxt/kit': 3.13.2(magicast@0.3.5)(rollup@4.22.0)(webpack-sources@3.2.3) + chokidar: 3.6.0 + ps-node: 0.1.6 + sirv: 2.0.4 + ufo: 1.5.4 + optionalDependencies: + '@rollup/rollup-linux-x64-gnu': 4.22.0 + transitivePeerDependencies: + - magicast + - rollup + - supports-color + - vite + - webpack-sources + nuxt-site-config-kit@2.2.18(magicast@0.3.5)(rollup@4.22.0)(vue@3.5.6(typescript@5.6.2))(webpack-sources@3.2.3): dependencies: '@nuxt/kit': 3.13.2(magicast@0.3.5)(rollup@4.22.0)(webpack-sources@3.2.3) @@ -11300,6 +11334,10 @@ snapshots: protocols@2.0.1: {} + ps-node@0.1.6: + dependencies: + table-parser: 0.1.3 + punycode@2.3.1: {} queue-microtask@1.2.3: {} @@ -11877,6 +11915,10 @@ snapshots: tabbable@6.2.0: {} + table-parser@0.1.3: + dependencies: + connected-domain: 1.0.0 + tailwind-config-viewer@2.0.4(tailwindcss@3.4.12): dependencies: '@koa/router': 12.0.2 diff --git a/src/module.ts b/src/module.ts index 0fb846af..8de2b239 100644 --- a/src/module.ts +++ b/src/module.ts @@ -13,7 +13,6 @@ import { } from '@nuxt/kit' import { joinURL, withBase, withLeadingSlash, withoutLeadingSlash, withoutTrailingSlash } from 'ufo' import { installNuxtSiteConfig } from 'nuxt-site-config-kit' -import type { NuxtI18nOptions } from '@nuxtjs/i18n' import { defu } from 'defu' import type { NitroRouteConfig } from 'nitropack' import { readPackageJSON } from 'pkg-types' @@ -26,7 +25,7 @@ import type { SitemapSourceBase, SitemapSourceInput, SitemapSourceResolved, - ModuleOptions as _ModuleOptions, FilterInput, + ModuleOptions as _ModuleOptions, FilterInput, I18nIntegrationOptions, } from './runtime/types' import { convertNuxtPagesToSitemapEntries, generateExtraRoutesFromNuxtConfig, resolveUrls } from './util/nuxtSitemap' import { createNitroPromise, createPagesPromise, extendTypes, getNuxtModuleOptions, resolveNitroPreset } from './util/kit' @@ -153,22 +152,26 @@ export default defineNuxtModule({ let usingMultiSitemaps = !!config.sitemaps let isI18nMapped = false - let nuxtI18nConfig = {} as NuxtI18nOptions + let nuxtI18nConfig = {} as I18nIntegrationOptions let resolvedAutoI18n: false | AutoI18nConfig = typeof config.autoI18n === 'boolean' ? false : config.autoI18n || false const hasDisabledAutoI18n = typeof config.autoI18n === 'boolean' && !config.autoI18n let normalisedLocales: AutoI18nConfig['locales'] = [] let usingI18nPages = false - if (hasNuxtModule('@nuxtjs/i18n')) { - const i18nVersion = await getNuxtModuleVersion('@nuxtjs/i18n') - if (!await hasNuxtModuleCompatibility('@nuxtjs/i18n', '>=8')) - logger.warn(`You are using @nuxtjs/i18n v${i18nVersion}. For the best compatibility, please upgrade to @nuxtjs/i18n v8.0.0 or higher.`) - nuxtI18nConfig = (await getNuxtModuleOptions('@nuxtjs/i18n') || {}) as NuxtI18nOptions + const i18nModule = ['@nuxtjs/i18n', 'nuxt-i18n-micro'].find(s => hasNuxtModule(s)) + if (i18nModule) { + const i18nVersion = await getNuxtModuleVersion(i18nModule) + if (i18nModule === '@nuxtjs/i18n' && !await hasNuxtModuleCompatibility(i18nModule, '>=8')) + logger.warn(`You are using ${i18nModule} v${i18nVersion}. For the best compatibility, please upgrade to ${i18nModule} v8.0.0 or higher.`) + nuxtI18nConfig = (await getNuxtModuleOptions(i18nModule) || {}) as I18nIntegrationOptions + if (typeof nuxtI18nConfig.includeDefaultLocaleRoute !== 'undefined') { + nuxtI18nConfig.strategy = nuxtI18nConfig.includeDefaultLocaleRoute ? 'prefix' : 'prefix_except_default' + } normalisedLocales = normalizeLocales(nuxtI18nConfig) usingI18nPages = !!Object.keys(nuxtI18nConfig.pages || {}).length if (usingI18nPages && !hasDisabledAutoI18n) { const i18nPagesSources: SitemapSourceBase = { context: { - name: '@nuxtjs/i18n:pages', + name: `${i18nModule}:pages`, description: 'Generated from your i18n.pages config.', tips: [ 'You can disable this with `autoI18n: false`.', @@ -213,7 +216,7 @@ export default defineNuxtModule({ } else { if (!normalisedLocales.length) - logger.warn(`You are using @nuxtjs/i18n but have not configured any locales, this will cause issues with ${name}. Please configure \`locales\`.`) + logger.warn(`You are using ${i18nModule} but have not configured any locales, this will cause issues with ${name}. Please configure \`locales\`.`) } const hasSetAutoI18n = typeof config.autoI18n === 'object' && Object.keys(config.autoI18n).length const hasI18nConfigForAlternatives = nuxtI18nConfig.differentDomains || usingI18nPages || (nuxtI18nConfig.strategy !== 'no_prefix' && nuxtI18nConfig.locales) diff --git a/src/runtime/types.ts b/src/runtime/types.ts index ddb4abd9..ba2dfe8e 100644 --- a/src/runtime/types.ts +++ b/src/runtime/types.ts @@ -1,6 +1,7 @@ import type { FetchOptions } from 'ofetch' import type { H3Event } from 'h3' import type { ParsedURL } from 'ufo' +import type { NuxtI18nOptions } from '@nuxtjs/i18n' // we need to have the module options within the runtime entry // as we don't want to depend on the module entry as it can cause @@ -446,3 +447,9 @@ export interface NitroUrlResolvers { relativeBaseUrlResolver: (path: string) => string fixSlashes: (path: string) => string } + +interface NuxtI18nMicro { + includeDefaultLocaleRoute?: boolean +} + +export type I18nIntegrationOptions = NuxtI18nOptions & NuxtI18nMicro diff --git a/test/fixtures/i18n-micro/locales/en.ts b/test/fixtures/i18n-micro/locales/en.ts new file mode 100644 index 00000000..4c03fbb9 --- /dev/null +++ b/test/fixtures/i18n-micro/locales/en.ts @@ -0,0 +1,3 @@ +export default { + welcome: 'Welcome', +} diff --git a/test/fixtures/i18n-micro/locales/hr.ts b/test/fixtures/i18n-micro/locales/hr.ts new file mode 100644 index 00000000..9800ad59 --- /dev/null +++ b/test/fixtures/i18n-micro/locales/hr.ts @@ -0,0 +1,3 @@ +export default { + welcome: 'ようこそ', +} diff --git a/test/fixtures/i18n-micro/locales/ja.ts b/test/fixtures/i18n-micro/locales/ja.ts new file mode 100644 index 00000000..9800ad59 --- /dev/null +++ b/test/fixtures/i18n-micro/locales/ja.ts @@ -0,0 +1,3 @@ +export default { + welcome: 'ようこそ', +} diff --git a/test/fixtures/i18n-micro/locales/nl.ts b/test/fixtures/i18n-micro/locales/nl.ts new file mode 100644 index 00000000..4c03fbb9 --- /dev/null +++ b/test/fixtures/i18n-micro/locales/nl.ts @@ -0,0 +1,3 @@ +export default { + welcome: 'Welcome', +} diff --git a/test/fixtures/i18n-micro/locales/zh.ts b/test/fixtures/i18n-micro/locales/zh.ts new file mode 100644 index 00000000..8409819d --- /dev/null +++ b/test/fixtures/i18n-micro/locales/zh.ts @@ -0,0 +1,3 @@ +export default { + welcome: '欢迎光临', +} diff --git a/test/fixtures/i18n-micro/nuxt.config.ts b/test/fixtures/i18n-micro/nuxt.config.ts new file mode 100644 index 00000000..ee25c7ec --- /dev/null +++ b/test/fixtures/i18n-micro/nuxt.config.ts @@ -0,0 +1,46 @@ +import NuxtSitemap from '../../../src/module' + +export default defineNuxtConfig({ + modules: [ + NuxtSitemap, + 'nuxt-i18n-micro', + ], + site: { + url: 'https://nuxtseo.com', + }, + nitro: { + prerender: { + failOnError: false, + ignore: ['/'], + }, + }, + sitemap: { + dynamicUrlsApiEndpoint: '/__sitemap', + autoLastmod: false, + credits: false, + debug: true, + }, + i18n: { + baseUrl: 'https://nuxtseo.com', + detectBrowserLanguage: false, + defaultLocale: 'en', + strategy: 'prefix', + locales: [ + { + code: 'en', + iso: 'en-US', + }, + { + code: 'es', + iso: 'es-ES', + }, + { + code: 'fr', + iso: 'fr-FR', + }, + ], + meta: true, + }, + + compatibilityDate: '2024-07-22', +}) diff --git a/test/fixtures/i18n-micro/pages/dynamic/[page].vue b/test/fixtures/i18n-micro/pages/dynamic/[page].vue new file mode 100644 index 00000000..39056864 --- /dev/null +++ b/test/fixtures/i18n-micro/pages/dynamic/[page].vue @@ -0,0 +1,3 @@ + diff --git a/test/fixtures/i18n-micro/pages/index.vue b/test/fixtures/i18n-micro/pages/index.vue new file mode 100644 index 00000000..366cc26a --- /dev/null +++ b/test/fixtures/i18n-micro/pages/index.vue @@ -0,0 +1,14 @@ + + + diff --git a/test/fixtures/i18n-micro/pages/test.vue b/test/fixtures/i18n-micro/pages/test.vue new file mode 100644 index 00000000..e16b1861 --- /dev/null +++ b/test/fixtures/i18n-micro/pages/test.vue @@ -0,0 +1,5 @@ + diff --git a/test/fixtures/i18n-micro/server/routes/__sitemap.ts b/test/fixtures/i18n-micro/server/routes/__sitemap.ts new file mode 100644 index 00000000..83a4cf89 --- /dev/null +++ b/test/fixtures/i18n-micro/server/routes/__sitemap.ts @@ -0,0 +1,11 @@ +import { defineSitemapEventHandler } from '#imports' + +export default defineSitemapEventHandler(() => { + return [ + { + loc: '/__sitemap/url', + changefreq: 'weekly', + _i18nTransform: true, + }, + ] +}) diff --git a/test/fixtures/i18n-micro/server/routes/i18n-urls.ts b/test/fixtures/i18n-micro/server/routes/i18n-urls.ts new file mode 100644 index 00000000..92bf4efd --- /dev/null +++ b/test/fixtures/i18n-micro/server/routes/i18n-urls.ts @@ -0,0 +1,21 @@ +import { defineSitemapEventHandler } from '#imports' + +export default defineSitemapEventHandler(() => { + return [ + { + loc: '/en/dynamic/foo', + }, + { + loc: '/fr/dynamic/foo', + }, + { + loc: 'endless-dungeon', // issue with en being picked up as the locale + _i18nTransform: true, + }, + { + loc: 'english-url', // issue with en being picked up as the locale + }, + // absolute URL issue + { loc: 'https://www.somedomain.com/abc/def' }, + ] +})