Skip to content

Commit

Permalink
fix(differentDomains): Match domain properly on client if port provid…
Browse files Browse the repository at this point in the history
…ed (nuxt-modules#832)

If the locale's "domain" contained a port then that wasn't matched correctly
on the client as it compared with "location.hostname" that doesn't include
the port. Use "location.host" instead.

With "vuex.syncLocale" set to to "true" the problem was not always
visible as a server-determined locale would be used on the client.
  • Loading branch information
rchl authored Sep 9, 2020
1 parent 0f7d301 commit 3a0bc88
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 11 deletions.
7 changes: 5 additions & 2 deletions docs/content/en/different-domains.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ category: Guide
You might want to use a different domain name for each language your app supports. To achieve this:

* Set `differentDomains` option to `true`
* Configure `locales` option as an array of object, where each object has a `domain` key which value is the domain name you'd like to use for the locale
* Configure `locales` option as an array of objects, where each object has a `domain` key which value is the domain name you'd like to use for that locale (including port if non-default)
* Optionally set `detectBrowserLanguage` to `false`. When enabled (which it is by default), user can get redirected to a different domain on first visit. Set to `false` if you want to ensure that visiting given domain always shows page in the corresponding locale.

</alert>

```js{}[nuxt.config.js]
Expand Down Expand Up @@ -46,7 +49,7 @@ When using different domain names, your lang swicher should use regular `<a>` ta

## Runtime environment variables

Sometimes there's a need to change domains in different environments, e.g. staging and production.
Sometimes there's a need to change domains in different environments, e.g. staging and production.
As `nuxt.config.js` is used at build time it would be necessary to create different builds for different environments.

The alternative way is to keep the domains in Vuex store under `localeDomains` property. It can be accessed by the plugin
Expand Down
3 changes: 2 additions & 1 deletion docs/content/es/different-domains.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ category: Guía
Es posible que desee utilizar un nombre de dominio diferente para cada idioma que admita su aplicación. Debe lograr esto:

* Establezca la opción `differentDomains` en `true`
* Configure la opción `locales` como una matriz de objetos, donde cada objeto tiene una clave `domain` cuyo valor es el nombre de dominio que desea usar para la configuración local
* Configure `locales` option as an array of objects, where each object has a `domain` key which value is the domain name you'd like to use for that locale (including port if non-default)
* Optionally set `detectBrowserLanguage` to `false`. When enabled (which it is by default), user can get redirected to a different domain on first visit. Set to `false` if you want to ensure that visiting given domain always shows page in the corresponding locale.

```js{}[nuxt.config.js]
Expand Down
14 changes: 7 additions & 7 deletions src/templates/utils-common.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,18 +85,18 @@ export const resolveBaseUrl = (baseUrl, context) => {
* @return {string | null} Locade code found if any
*/
export const getLocaleDomain = (locales, req, { localDomainKey, localeCodeKey }) => {
let hostname = null
let host = null

if (process.client) {
hostname = window.location.hostname
host = window.location.host
} else if (req) {
hostname = req.headers['x-forwarded-host'] || req.headers.host
host = req.headers['x-forwarded-host'] || req.headers.host
}

if (hostname) {
const localeDomain = locales.find(l => l[localDomainKey] === hostname)
if (localeDomain) {
return localeDomain[localeCodeKey]
if (host) {
const matchingLocale = locales.find(l => l[localDomainKey] === host)
if (matchingLocale) {
return matchingLocale[localeCodeKey]
}
}

Expand Down
57 changes: 56 additions & 1 deletion test/browser.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { resolve } from 'path'
import { generate, setup, loadConfig, url } from '@nuxtjs/module-test-utils'
import { generate, setup, loadConfig, url, generatePort } from '@nuxtjs/module-test-utils'
import { chromium } from 'playwright-chromium'
import { startHttpServer } from './utils'

Expand Down Expand Up @@ -785,3 +785,58 @@ describe(`${browserString} (vuex disabled)`, () => {
expect(await (await page2.$('body'))?.textContent()).toContain('locale: fr')
})
})

describe('differentDomains', () => {
/** @type {Nuxt} */
let nuxt
/** @type {import('playwright-chromium').ChromiumBrowser} */
let browser
let port

beforeAll(async () => {
port = await generatePort()
const overrides = {
i18n: {
detectBrowserLanguage: false,
differentDomains: true,
seo: false,
vuex: false
}
}

const localConfig = loadConfig(__dirname, 'basic', overrides, { merge: true })

// Override after merging options to avoid arrays being merged.
localConfig.i18n.locales = [
{
code: 'en',
iso: 'en-US',
name: 'English',
domain: 'en.nuxt-app.localhost'
},
{
code: 'fr',
iso: 'fr-FR',
name: 'Français',
// Since we can't use custom domain in browser test, we'll make FR locale match the used one.
domain: `localhost:${port}`
}
]

nuxt = (await setup(localConfig, { port })).nuxt
browser = await createBrowser()
})

afterAll(async () => {
if (browser) {
await browser.close()
}
await nuxt.close()
})

test('navigates to route with correct locale', async () => {
const page = await browser.newPage()
await page.goto(url('/'))
expect(await (await page.$('body'))?.textContent()).toContain('locale: fr')
})
})

0 comments on commit 3a0bc88

Please sign in to comment.