Skip to content

Commit

Permalink
feat: support detect browser language fully (#1534)
Browse files Browse the repository at this point in the history
* feat: support detect browser language fully

* fix

* refactor

* fix lint warnings

* update snapshot

* remove comment

* fix: redirection on `setLocale`

* fix: browser language detection fully supporting

* update deps
  • Loading branch information
kazupon authored Sep 28, 2022
1 parent ee9bcc7 commit b660dc2
Show file tree
Hide file tree
Showing 35 changed files with 637 additions and 281 deletions.
5 changes: 0 additions & 5 deletions docs/content/30.guide/6.browser-language-detection.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@ title: Browser language detection
description: "By default, @nuxtjs/i18n attempts to redirect users to their preferred language by detecting their browser's language. This is controlled by the `detectBrowserLanguage` option:"
---

::alert{type="warning"}
// TODO:
🚧 This feature is not implemented **fully** yet.
::

By default, **@nuxtjs/i18n** attempts to redirect users to their preferred language by detecting their browser's language. This is controlled by the `detectBrowserLanguage` option:

```js {}[nuxt.config.js]
Expand Down
5 changes: 0 additions & 5 deletions docs/content/30.guide/9.lang-switcher.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,6 @@ export default defineNuxtConfig({
})
```

::alert{type="info"}
// TODO:
🚧 This feature is not implemented **fully** yet.
::

::alert{type="info"}
When using `detectBrowserLanguage` and wanting to persist locale on a route change, you must call one of the functions that update the stored locale cookie. Call either [`setLocaleCookie(locale)`](/api#setlocalecookie) to persist just the cookie locale or [`setLocale(locale)`](/api#setlocale) to both persist the cookie locale and switch the route to the specified locale. Otherwise, locale might switch back to the saved one during navigation.
::
Expand Down
5 changes: 0 additions & 5 deletions docs/content/40.options/4.browser.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@ description: Browser locale management options

## `detectBrowserLanguage`

::alert{type="warning"}
// TODO:
🚧 This feature is not implemented **fully** yet.
::

- type: `object`
- default: `{ alwaysRedirect: false, fallbackLocale: '', redirectOn: 'root', useCookie: true, cookieCrossOrigin: false, cookieDomain: null, cookieKey: 'i18n_redirected', cookieSecure: false }`

Expand Down
11 changes: 5 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@
"test:spec": "yarn build && vitest run specs"
},
"dependencies": {
"@intlify/bundle-utils": "^3.1.2",
"@intlify/shared": "9.3.0-beta.3",
"@intlify/unplugin-vue-i18n": "^0.6.0",
"@intlify/bundle-utils": "^3.2.1",
"@intlify/shared": "9.3.0-beta.6",
"@intlify/unplugin-vue-i18n": "^0.7.0",
"@nuxt/kit": "^3.0.0-rc.9",
"cookie-es": "^0.5.0",
"debug": "^4.3.2",
Expand All @@ -77,9 +77,8 @@
"knitwork": "^0.1.2",
"mlly": "^0.5.4",
"pathe": "^0.3.2",
"vue-i18n": "^9.3.0-beta.3",
"vue-i18n-bridge": "^9.3.0-beta.3",
"vue-i18n-routing": "^0.2.0"
"vue-i18n": "^9.3.0-beta.6",
"vue-i18n-routing": "^0.3.0"
},
"devDependencies": {
"@babel/parser": "^7.17.9",
Expand Down
19 changes: 12 additions & 7 deletions playground/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,26 @@ export default defineNuxtConfig({
name: 'Français'
}
],
debug: true,
defaultLocale: 'en',
strategy: 'no_prefix',
// strategy: 'prefix',
// strategy: 'prefix_and_default',
pages: {
about: {
ja: '/about-ja'
}
},
detectBrowserLanguage: false,
// detectBrowserLanguage: {
// useCookie: true,
// cookieKey: 'i18n_redirected',
// redirectOn: 'all'
// },
// detectBrowserLanguage: false,
detectBrowserLanguage: {
// alwaysRedirect: true,
useCookie: false
// cookieKey: 'i18n_redirected',
// cookieKey: 'my_custom_cookie_name',
// redirectOn: 'root'
},
onBeforeLanguageSwitch: (oldLocale, newLocale, initial, context) => {
console.log('onBeforeLanguageSwitch', oldLocale, newLocale, initial, context)
console.log('onBeforeLanguageSwitch', oldLocale, newLocale, initial)
},
onLanguageSwitched: (oldLocale, newLocale) => {
console.log('onLanguageSwitched', oldLocale, newLocale)
Expand Down
8 changes: 8 additions & 0 deletions playground/pages/about/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ export default defineComponent({
console.log('$i18n.localeProperties', this.$i18n.localeProperties)
},
computed: {
availableLocales() {
return (this.$i18n.locales as LocaleObject[]).filter(i => i.code !== this.$i18n.locale)
},
switchableLocale() {
const i18n = this.$i18n as ExportedGlobalComposer
const _locales = (i18n.locales as LocaleObject[]).filter(i => i.code !== this.$i18n.locale)
Expand Down Expand Up @@ -37,6 +40,11 @@ definePageMeta({
<NuxtLink :to="localePath('/')">Back to Home</NuxtLink>
</nav>
<p>hello</p>
<nav>
<span v-for="locale in availableLocales" :key="locale.code">
<a href="javascript:void(0)" @click="$i18n.setLocale(locale.code)">{{ locale.name }}</a> |
</span>
</nav>
<p>{{ switchableLocale }}</p>
<p>{{ localeHead({ addSeoAttributes: true }) }}</p>
</div>
Expand Down
2 changes: 1 addition & 1 deletion playground/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const availableLocales = computed(() => {
<h2>Select Languages with setLocale</h2>
<nav>
<span v-for="locale in availableLocales" :key="locale.code">
<a href="#" @click="setLocale(locale.code)">{{ locale.name }}</a> |
<a href="javascript:void(0)" @click="setLocale(locale.code)">{{ locale.name }}</a> |
</span>
</nav>
</div>
Expand Down
47 changes: 47 additions & 0 deletions specs/browser_language_detection/browser.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { test, expect } from 'vitest'
import { fileURLToPath } from 'node:url'
import { setup, url, createPage } from '@nuxt/test-utils'
import { getText } from '../helper'

await setup({
rootDir: fileURLToPath(new URL(`../fixtures/basic`, import.meta.url)),
browser: true,
// overrides
nuxtConfig: {
i18n: {
strategy: 'no_prefix',
detectBrowserLanguage: {
useCookie: false
}
}
}
})

test('detection with browser', async () => {
const home = url('/')
const page = await createPage(undefined, { locale: 'fr' }) // set browser locale
await page.goto(home)

// detect locale from navigator language
expect(await getText(page, '#lang-switcher-current-locale code')).toEqual('fr')

// click `en` lang switch link
await page.locator('#set-locale-link-en').click()
expect(await getText(page, '#lang-switcher-current-locale code')).toEqual('en')

// navigate to blog/article
await page.goto(url('/blog/article'))

// locale in blog/article
expect(await getText(page, '#lang-switcher-current-locale code')).toEqual('fr')

// navigate with home
await page.goto(url('/'))

// locale in home
expect(await getText(page, '#lang-switcher-current-locale code')).toEqual('fr')

// click `en` lang switch link
await page.locator('#set-locale-link-en').click()
expect(await getText(page, '#lang-switcher-current-locale code')).toEqual('en')
})
51 changes: 51 additions & 0 deletions specs/browser_language_detection/cookie.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { test, expect } from 'vitest'
import { fileURLToPath } from 'node:url'
import { setup, url, createPage } from '@nuxt/test-utils'
import { getText } from '../helper'

await setup({
rootDir: fileURLToPath(new URL(`../fixtures/basic`, import.meta.url)),
browser: true,
// overrides
nuxtConfig: {
i18n: {
strategy: 'no_prefix',
detectBrowserLanguage: {
useCookie: true,
cookieKey: 'my_custom_cookie_name',
redirectOn: 'root',
cookieCrossOrigin: true,
cookieSecure: true
}
}
}
})

test('detection with cookie', async () => {
const home = url('/')
const page = await createPage(undefined, { locale: 'en' })
await page.goto(home)
const ctx = await page.context()

// click `fr` lang switch link
await page.locator('#set-locale-link-fr').click()
expect(await ctx.cookies()).toMatchObject([
{ name: 'my_custom_cookie_name', value: 'fr', secure: true, sameSite: 'None' }
])

// navigate to about
await page.goto(url('/about'))

// detect locale from persisted cookie
expect(await getText(page, '#lang-switcher-current-locale code')).toEqual('fr')

// navigate with home link
await page.locator('#link-home').click()

// locale in home
expect(await getText(page, '#lang-switcher-current-locale code')).toEqual('fr')

// click `fr` lang switch link
await page.locator('#set-locale-link-en').click()
expect(await ctx.cookies()).toMatchObject([{ name: 'my_custom_cookie_name', value: 'en' }])
})
42 changes: 42 additions & 0 deletions specs/browser_language_detection/disable.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { test, expect } from 'vitest'
import { fileURLToPath } from 'node:url'
import { setup, url, createPage } from '@nuxt/test-utils'
import { getText } from '../helper'

await setup({
rootDir: fileURLToPath(new URL(`../fixtures/basic`, import.meta.url)),
browser: true,
// overrides
nuxtConfig: {
i18n: {
strategy: 'no_prefix',
detectBrowserLanguage: false
}
}
})

test('disable', async () => {
const home = url('/')
const page = await createPage(undefined, { locale: 'en' })
await page.goto(home)
const ctx = await page.context()

// click `fr` lang switch link
await page.locator('#set-locale-link-fr').click()
expect(await ctx.cookies()).toMatchObject([])

// navigate to about
await page.goto(url('/about'))

// set default locale
expect(await getText(page, '#lang-switcher-current-locale code')).toEqual('en')

// click `fr` lang switch link
await page.locator('#set-locale-link-fr').click()

// navigate with home link
await page.locator('#link-home').click()

// set default locale
expect(await getText(page, '#lang-switcher-current-locale code')).toEqual('en')
})
29 changes: 29 additions & 0 deletions specs/browser_language_detection/fallback.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { test, expect } from 'vitest'
import { fileURLToPath } from 'node:url'
import { setup, url, createPage } from '@nuxt/test-utils'
import { getText } from '../helper'

await setup({
rootDir: fileURLToPath(new URL(`../fixtures/basic`, import.meta.url)),
browser: true,
// overrides
nuxtConfig: {
i18n: {
strategy: 'no_prefix',
defaultLocale: 'en',
detectBrowserLanguage: {
useCookie: false,
fallbackLocale: 'fr'
}
}
}
})

test('fallback', async () => {
const home = url('/')
const page = await createPage(undefined, { locale: 'ja' }) // set browser locale
await page.goto(home)

// detect fallback locale with navigator language
expect(await getText(page, '#lang-switcher-current-locale code')).toEqual('fr')
})
35 changes: 35 additions & 0 deletions specs/browser_language_detection/redirect_all.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { test, expect } from 'vitest'
import { fileURLToPath } from 'node:url'
import { setup, url, createPage } from '@nuxt/test-utils'
import { getText } from '../helper'

await setup({
rootDir: fileURLToPath(new URL(`../fixtures/basic`, import.meta.url)),
browser: true,
// overrides
nuxtConfig: {
i18n: {
strategy: 'prefix_except_default',
detectBrowserLanguage: {
redirectOn: 'all'
}
}
}
})

test('redirectOn: all', async () => {
const blog = url('/blog/article')
const page = await createPage(undefined, { locale: 'fr' }) // set browser locale
await page.goto(blog)

// detect locale from navigator language
expect(await getText(page, '#lang-switcher-current-locale code')).toEqual('en')

// click `fr` lang switch link
await page.locator('#set-locale-link-fr').click()
expect(await getText(page, '#lang-switcher-current-locale code')).toEqual('fr')

// navigate to home
await page.goto(url('/'))
expect(await getText(page, '#lang-switcher-current-locale code')).toEqual('en')
})
36 changes: 36 additions & 0 deletions specs/browser_language_detection/redirect_no_prefix.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { test, expect } from 'vitest'
import { fileURLToPath } from 'node:url'
import { setup, url, createPage } from '@nuxt/test-utils'
import { getText } from '../helper'

await setup({
rootDir: fileURLToPath(new URL(`../fixtures/basic`, import.meta.url)),
browser: true,
// overrides
nuxtConfig: {
i18n: {
strategy: 'prefix_and_default',
detectBrowserLanguage: {
alwaysRedirect: false,
redirectOn: 'no prefix'
}
}
}
})

test('redirectOn: no prefix', async () => {
const blog = url('/blog/article')
const page = await createPage(undefined, { locale: 'fr' }) // set browser locale
await page.goto(blog)

// detect locale from navigator language
expect(await getText(page, '#lang-switcher-current-locale code')).toEqual('en')

// click `fr` lang switch link
await page.locator('#set-locale-link-fr').click()
expect(await getText(page, '#lang-switcher-current-locale code')).toEqual('fr')

// navigate to home
await page.goto(url('/'))
expect(await getText(page, '#lang-switcher-current-locale code')).toEqual('en')
})
Loading

0 comments on commit b660dc2

Please sign in to comment.