Skip to content

Commit

Permalink
fix: make the message compiler work on the server side (#2223)
Browse files Browse the repository at this point in the history
* fix: make the message compiler work on the server side

* fix
  • Loading branch information
kazupon authored Jul 11, 2023
1 parent 8d65ac4 commit d05ca82
Show file tree
Hide file tree
Showing 15 changed files with 177 additions and 10 deletions.
1 change: 0 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ This changelog is generated by [GitHub Releases](https://github.com/nuxt-modules

#####     [View changes on GitHub](https://github.com/nuxt-modules/i18n/compare/v8.0.0-beta.12...v8.0.0-beta.13)


# v8.0.0-beta.12 (2023-05-11T14:39:12Z)

This changelog is generated by [GitHub Releases](https://github.com/nuxt-modules/i18n/releases/tag/v8.0.0-beta.12)
Expand Down
19 changes: 19 additions & 0 deletions specs/fixtures/issues/2220/app.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<template>
<div id="app">
{{ env }}
{{ data }}
<div v-if="correct && env == 'DEV'">working in dev as intended</div>
<div v-if="!correct && env == 'DEV'">wtf now it's not working even in dev?</div>

<div v-if="!correct && env == 'PROD'">unfortunately still doesn't work in prod</div>
<div v-if="correct && env == 'PROD'">yeah! it's finally working in prod too</div>
</div>
</template>

<script setup lang="ts">
const data = ref([])
const env = process.dev ? 'DEV' : 'PROD'
const correct = computed(() => ['Test', 'Тест'].includes(data.value[0]))
data.value = await $fetch('/api/foo')
</script>
10 changes: 10 additions & 0 deletions specs/fixtures/issues/2220/locales.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export default [
{
code: 'en',
name: 'English'
},
{
code: 'ru',
name: 'Русский'
}
].map(lang => ({ file: lang.code + '.json', ...lang }))
3 changes: 3 additions & 0 deletions specs/fixtures/issues/2220/locales/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"test": "Test"
}
3 changes: 3 additions & 0 deletions specs/fixtures/issues/2220/locales/ru.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"test": "Тест"
}
13 changes: 13 additions & 0 deletions specs/fixtures/issues/2220/nuxt.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import locales from './locales'

export default defineNuxtConfig({
modules: ['@nuxtjs/i18n'],
i18n: {
lazy: true,
langDir: 'locales',
locales,
defaultLocale: 'en',
detectBrowserLanguage: false,
strategy: 'no_prefix'
}
})
14 changes: 14 additions & 0 deletions specs/fixtures/issues/2220/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "nuxt3-test-issues-2220",
"private": true,
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview"
},
"devDependencies": {
"@nuxtjs/i18n": "latest",
"nuxt": "latest"
}
}
3 changes: 3 additions & 0 deletions specs/fixtures/issues/2220/server/api/foo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default defineEventHandler(e => {
return [e.context.$t('test')]
})
28 changes: 28 additions & 0 deletions specs/fixtures/issues/2220/server/middleware/i18n.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { defineEventHandler, getCookie } from 'h3'
import { createI18n } from 'vue-i18n'
import locales from '../../locales'
import en from '../../locales/en.json'
import ru from '../../locales/ru.json'

const resources = {
en,
ru
}

const i18n = createI18n({
fallbackLocale: 'en'
}).global

for (const { code } of locales) {
i18n.setLocaleMessage(code, resources[code])
}

export default defineEventHandler(e => {
e.context.$t = (key: string) => i18n.t(key, getCookie(e, 'lang') || i18n.fallbackLocale.toString())
})

declare module 'h3' {
interface H3EventContext {
$t: typeof i18n.t
}
}
19 changes: 19 additions & 0 deletions specs/issues/2220.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { test, expect, describe } from 'vitest'
import { fileURLToPath } from 'node:url'
import { setup, createPage, url } from '../utils'
import { getText } from '../helper'

describe('#2220', async () => {
await setup({
rootDir: fileURLToPath(new URL(`../fixtures/issues/2220`, import.meta.url))
})

test('message-compiler work on server-side', async () => {
const home = url('/')
const page = await createPage()
await page.goto(home)

expect(await getText(page, '#app')).include('PROD [ "Test" ]')
expect(await getText(page, '#app')).include(`yeah! it's finally working in prod too`)
})
})
32 changes: 30 additions & 2 deletions src/alias.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import createDebug from 'debug'
import { resolvePath } from '@nuxt/kit'
import { pkgModulesDir } from './dirs'
import { resolve } from 'pathe'
import { VUE_I18N_PKG, VUE_I18N_BRIDGE_PKG, VUE_ROUTER_BRIDGE_PKG, VUE_I18N_ROUTING_PKG } from './constants'
import {
VUE_I18N_PKG,
VUE_I18N_BRIDGE_PKG,
VUE_ROUTER_BRIDGE_PKG,
VUE_I18N_ROUTING_PKG,
MESSAGE_COMPILER_PKG
} from './constants'
import { pkgModulesDir } from './dirs'
import { tryResolve, getLayerRootDirs, getPackageManagerType } from './utils'

import type { Nuxt } from '@nuxt/schema'
Expand All @@ -24,6 +30,10 @@ export async function setupAlias(nuxt: Nuxt) {
nuxt.options.build.transpile.push('@intlify/shared')
debug('@intlify/shared alias', nuxt.options.alias['@intlify/shared'])

nuxt.options.alias['@intlify/message-compiler'] = await resolveMessageCompilerAlias(pkgModulesDir, nuxt, pkgMgr)
nuxt.options.build.transpile.push('@intlify/message-compiler')
debug('@intlify/message-compiler alias', nuxt.options.alias['@intlify/message-compiler'])

// resolve @intlify/vue-router-bridge
nuxt.options.alias[VUE_ROUTER_BRIDGE_PKG] = await resolveVueRouterBridgeAlias(pkgModulesDir, nuxt, pkgMgr)
nuxt.options.build.transpile.push(VUE_ROUTER_BRIDGE_PKG)
Expand Down Expand Up @@ -136,3 +146,21 @@ export async function resolveVueI18nRoutingAlias(pkgModulesDir: string, nuxt: Nu

return tryResolve(VUE_I18N_ROUTING_PKG, targets, pkgMgr)
}

export async function resolveMessageCompilerAlias(pkgModulesDir: string, nuxt: Nuxt, pkgMgr: PackageManager) {
const { rootDir, workspaceDir } = nuxt.options
const modulePath = `${MESSAGE_COMPILER_PKG}/dist/message-compiler.mjs` as const
const targets = [
// for Nuxt layer
...getLayerRootDirs(nuxt).map(root => resolve(root, 'node_modules', modulePath)),
// 1st, try to resolve from `node_modules` (hoisted case)
resolve(rootDir, 'node_modules', modulePath),
// 2nd, try to resolve from `node_modules/@nuxtjs/i18n` (not hoisted case)
resolve(pkgModulesDir, modulePath),
// workspace directories
resolve(workspaceDir, 'node_modules', modulePath)
]
debug(`${MESSAGE_COMPILER_PKG} resolving from ...`, targets)

return tryResolve(MESSAGE_COMPILER_PKG, targets, pkgMgr)
}
18 changes: 11 additions & 7 deletions src/bundler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import VueI18nVitePlugin from '@intlify/unplugin-vue-i18n/vite'
import { TransformMacroPlugin, TransformMacroPluginOptions } from './transform/macros'
import { ResourceProxyPlugin, ResourceProxyPluginOptions } from './transform/proxy'
import { ResourceDynamicPlugin, ResourceDynamicPluginOptions } from './transform/dynamic'
import { assign } from '@intlify/shared'
import { getLayerLangPaths } from './layers'

import type { Nuxt } from '@nuxt/schema'
Expand Down Expand Up @@ -86,13 +87,7 @@ export async function extendBundler(
extendWebpackConfig(config => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- `config.plugins` is safe, so it's assigned with nuxt!
config.plugins!.push(
new webpack.DefinePlugin({
__VUE_I18N_FULL_INSTALL__: 'true',
__VUE_I18N_LEGACY_API__: 'true',
__INTLIFY_PROD_DEVTOOLS__: 'false',
__INTLIFY_JIT_COMPILATION__: 'true',
__DEBUG__: JSON.stringify(nuxtOptions.debug)
})
new webpack.DefinePlugin(assign(getFeatureFlags(), { __DEBUG__: String(nuxtOptions.debug) }))
)
})
} catch (e: unknown) {
Expand Down Expand Up @@ -130,3 +125,12 @@ export async function extendBundler(
debug('vite.config.define', config.define)
})
}

export function getFeatureFlags() {
return {
__VUE_I18N_FULL_INSTALL__: 'true',
__VUE_I18N_LEGACY_API__: 'true',
__INTLIFY_PROD_DEVTOOLS__: 'false',
__INTLIFY_JIT_COMPILATION__: 'true'
}
}
1 change: 1 addition & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const VUE_I18N_PKG = 'vue-i18n' as const
export const VUE_I18N_BRIDGE_PKG = '@intlify/vue-i18n-bridge' as const
export const VUE_ROUTER_BRIDGE_PKG = '@intlify/vue-router-bridge' as const
export const VUE_I18N_ROUTING_PKG = 'vue-i18n-routing' as const
export const MESSAGE_COMPILER_PKG = '@intlify/message-compiler' as const

// Options
const STRATEGY_PREFIX = 'prefix'
Expand Down
7 changes: 7 additions & 0 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { resolve, relative, isAbsolute } from 'pathe'
import { defu } from 'defu'
import { setupAlias, resolveVueI18nAlias } from './alias'
import { setupPages } from './pages'
import { setupNitro } from './nitro'
import { extendMessages } from './messages'
import { extendBundler } from './bundler'
import { generateLoaderOptions } from './gen'
Expand Down Expand Up @@ -283,6 +284,12 @@ export default defineNuxtModule<NuxtI18nOptions>({
langPath
})

/**
* setup nitro
*/

await setupNitro(nuxt)

/**
* auto imports
*/
Expand Down
16 changes: 16 additions & 0 deletions src/nitro.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { assign } from '@intlify/shared'
import { getFeatureFlags } from './bundler'

import type { Nuxt } from '@nuxt/schema'

export async function setupNitro(nuxt: Nuxt) {
if (nuxt.options.ssr) {
if (!nuxt.options.nitro) {
nuxt.options.nitro = {}
}
const nitroConfig = nuxt.options.nitro

// vue-i18n feature flags configuration for server-side (server api, server middleware, etc...)
nitroConfig.replace = assign(nitroConfig.replace || {}, getFeatureFlags())
}
}

0 comments on commit d05ca82

Please sign in to comment.