Skip to content

Commit 952fc9d

Browse files
authored
feat: add identifierAttribute option for useLocaleHead and localeHead (#9)
1 parent 05b0b9c commit 952fc9d

File tree

5 files changed

+123
-53
lines changed

5 files changed

+123
-53
lines changed

packages/vue-i18n-routing/src/compatibles/head.ts

+30-13
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import type { I18nHeadOptions, I18nHeadMetaInfo, MetaAttrs, RoutingProxy } from
1111

1212
export function localeHead(
1313
this: RoutingProxy,
14-
{ addDirAttribute = false, addSeoAttributes = false }: I18nHeadOptions = {}
14+
{ addDirAttribute = false, addSeoAttributes = false, identifierAttribute = 'hid' }: I18nHeadOptions = {}
1515
): I18nHeadMetaInfo {
1616
const router = this.router
1717
const i18n = this.i18n
@@ -46,16 +46,22 @@ export function localeHead(
4646
metaObject.htmlAttrs.lang = currentLocaleIso
4747
}
4848

49-
addHreflangLinks.call(this, locales as LocaleObject[], i18n.__baseUrl, metaObject.link)
50-
addCanonicalLinks.call(this, i18n.__baseUrl, metaObject.link, addSeoAttributes)
51-
addCurrentOgLocale(currentLocale, currentLocaleIso, metaObject.meta)
52-
addAlternateOgLocales(locales as LocaleObject[], currentLocaleIso, metaObject.meta)
49+
addHreflangLinks.call(this, locales as LocaleObject[], i18n.__baseUrl, metaObject.link, identifierAttribute)
50+
addCanonicalLinks.call(this, i18n.__baseUrl, metaObject.link, identifierAttribute, addSeoAttributes)
51+
addCurrentOgLocale(currentLocale, currentLocaleIso, metaObject.meta, identifierAttribute)
52+
addAlternateOgLocales(locales as LocaleObject[], currentLocaleIso, metaObject.meta, identifierAttribute)
5353
}
5454

5555
return metaObject
5656
}
5757

58-
function addHreflangLinks(this: RoutingProxy, locales: LocaleObject[], baseUrl: string, link: MetaAttrs) {
58+
function addHreflangLinks(
59+
this: RoutingProxy,
60+
locales: LocaleObject[],
61+
baseUrl: string,
62+
link: MetaAttrs,
63+
identifierAttribute: NonNullable<I18nHeadOptions['identifierAttribute']>
64+
) {
5965
const router = this.router
6066
const { defaultLocale, strategy } = getI18nRoutingOptions(router, this)
6167
if (strategy === STRATEGIES.NO_PREFIX) {
@@ -84,7 +90,7 @@ function addHreflangLinks(this: RoutingProxy, locales: LocaleObject[], baseUrl:
8490
const localePath = switchLocalePath.call(this, mapLocale.code)
8591
if (localePath) {
8692
link.push({
87-
hid: `i18n-alt-${iso}`,
93+
[identifierAttribute]: `i18n-alt-${iso}`,
8894
rel: 'alternate',
8995
href: toAbsoluteUrl(localePath, baseUrl),
9096
hreflang: iso
@@ -96,7 +102,7 @@ function addHreflangLinks(this: RoutingProxy, locales: LocaleObject[], baseUrl:
96102
const localePath = switchLocalePath.call(this, defaultLocale)
97103
if (localePath) {
98104
link.push({
99-
hid: 'i18n-xd',
105+
[identifierAttribute]: 'i18n-xd',
100106
rel: 'alternate',
101107
href: toAbsoluteUrl(localePath, baseUrl),
102108
hreflang: 'x-default'
@@ -109,6 +115,7 @@ function addCanonicalLinks(
109115
this: RoutingProxy,
110116
baseUrl: string,
111117
link: MetaAttrs,
118+
identifierAttribute: NonNullable<I18nHeadOptions['identifierAttribute']>,
112119
seoAttributesOptions: I18nHeadOptions['addSeoAttributes']
113120
) {
114121
const route = this.route
@@ -145,37 +152,47 @@ function addCanonicalLinks(
145152
}
146153

147154
link.push({
148-
hid: 'i18n-can',
155+
[identifierAttribute]: 'i18n-can',
149156
rel: 'canonical',
150157
href
151158
})
152159
}
153160
}
154161

155-
function addCurrentOgLocale(currentLocale: LocaleObject, currentLocaleIso: string | undefined, meta: MetaAttrs) {
162+
function addCurrentOgLocale(
163+
currentLocale: LocaleObject,
164+
currentLocaleIso: string | undefined,
165+
meta: MetaAttrs,
166+
identifierAttribute: NonNullable<I18nHeadOptions['identifierAttribute']>
167+
) {
156168
const hasCurrentLocaleAndIso = currentLocale && currentLocaleIso
157169

158170
if (!hasCurrentLocaleAndIso) {
159171
return
160172
}
161173

162174
meta.push({
163-
hid: 'i18n-og',
175+
[identifierAttribute]: 'i18n-og',
164176
property: 'og:locale',
165177
// Replace dash with underscore as defined in spec: language_TERRITORY
166178
content: hypenToUnderscore(currentLocaleIso)
167179
})
168180
}
169181

170-
function addAlternateOgLocales(locales: LocaleObject[], currentLocaleIso: string | undefined, meta: MetaAttrs) {
182+
function addAlternateOgLocales(
183+
locales: LocaleObject[],
184+
currentLocaleIso: string | undefined,
185+
meta: MetaAttrs,
186+
identifierAttribute: NonNullable<I18nHeadOptions['identifierAttribute']>
187+
) {
171188
const localesWithoutCurrent = locales.filter(locale => {
172189
const localeIso = locale.iso
173190
return localeIso && localeIso !== currentLocaleIso
174191
})
175192

176193
if (localesWithoutCurrent.length) {
177194
const alternateLocales = localesWithoutCurrent.map(locale => ({
178-
hid: `i18n-og-alt-${locale.iso}`,
195+
[identifierAttribute]: `i18n-og-alt-${locale.iso}`,
179196
property: 'og:locale:alternate',
180197
content: hypenToUnderscore(locale.iso!)
181198
}))

packages/vue-i18n-routing/src/compatibles/types.ts

+6
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ export interface I18nHeadOptions {
5353
* @defaultValue false
5454
*/
5555
addSeoAttributes?: boolean | SeoAttributesOptions
56+
/**
57+
* Identifier attribute of `<meta>` tag
58+
*
59+
* @defaultValue 'hid'
60+
*/
61+
identifierAttribute?: string
5662
}
5763

5864
export type MetaAttrs = Record<string, any>

packages/vue-i18n-routing/src/composables/__test__/__snapshots__/head.test.ts.snap

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Vitest Snapshot v1
22

3-
exports[`useLocaleHead > should be worked > en 1`] = `
3+
exports[`useLocaleHead > basic > should be worked > en 1`] = `
44
{
55
"htmlAttrs": {
66
"dir": "ltr",
@@ -52,7 +52,7 @@ exports[`useLocaleHead > should be worked > en 1`] = `
5252
}
5353
`;
5454

55-
exports[`useLocaleHead > should be worked > ja 1`] = `
55+
exports[`useLocaleHead > basic > should be worked > ja 1`] = `
5656
{
5757
"htmlAttrs": {
5858
"dir": "ltr",

packages/vue-i18n-routing/src/composables/__test__/head.test.ts

+83-37
Original file line numberDiff line numberDiff line change
@@ -7,46 +7,92 @@ import { createRouter } from '../../extends/router'
77
import { useLocaleHead } from '../head'
88

99
describe('useLocaleHead', () => {
10-
it('should be worked', async () => {
11-
const i18n = createI18n({ legacy: false, locale: 'en' })
12-
const router = createRouter(i18n, {
13-
version: 4,
14-
locales: [
15-
{
16-
code: 'en',
17-
iso: 'en-US',
18-
dir: 'ltr'
19-
},
20-
{
21-
code: 'ja',
22-
iso: 'ja-JP'
10+
describe('basic', () => {
11+
it('should be worked', async () => {
12+
const i18n = createI18n({ legacy: false, locale: 'en' })
13+
const router = createRouter(i18n, {
14+
version: 4,
15+
locales: [
16+
{
17+
code: 'en',
18+
iso: 'en-US',
19+
dir: 'ltr'
20+
},
21+
{
22+
code: 'ja',
23+
iso: 'ja-JP'
24+
}
25+
],
26+
baseUrl: 'http://localhost:8080',
27+
routes: [
28+
{ path: '/', name: 'index', component: { template: '<div>index</div>' } },
29+
{ path: '/about', name: 'about', component: { template: '<div>About</div>' } },
30+
{ path: '/:pathMatch(.*)*', name: 'not-found', component: { template: '<div>Not Found</div>' } }
31+
],
32+
history: createMemoryHistory()
33+
})
34+
await router.push('/en/about')
35+
36+
const vm = useSetup(() => {
37+
const route = useRoute()
38+
const router = useRouter()
39+
const i18n = useI18n()
40+
const head = useLocaleHead({ addDirAttribute: true, addSeoAttributes: true, route, router, i18n })
41+
expect(head.value).toMatchSnapshot(i18n.locale.value)
42+
assert.equal(head.value.htmlAttrs!.lang, 'en-US')
43+
return {
44+
i18n,
45+
head
2346
}
24-
],
25-
baseUrl: 'http://localhost:8080',
26-
routes: [
27-
{ path: '/', name: 'index', component: { template: '<div>index</div>' } },
28-
{ path: '/about', name: 'about', component: { template: '<div>About</div>' } },
29-
{ path: '/:pathMatch(.*)*', name: 'not-found', component: { template: '<div>Not Found</div>' } }
30-
],
31-
history: createMemoryHistory()
47+
}, [router, i18n])
48+
49+
await router.push('/ja')
50+
expect(vm.head).toMatchSnapshot(vm.i18n.locale.value)
51+
assert.equal(vm.head.htmlAttrs!.lang, 'ja-JP')
3252
})
33-
await router.push('/en/about')
53+
})
3454

35-
const vm = useSetup(() => {
36-
const route = useRoute()
37-
const router = useRouter()
38-
const i18n = useI18n()
39-
const head = useLocaleHead({ addDirAttribute: true, addSeoAttributes: true, route, router, i18n })
40-
expect(head.value).toMatchSnapshot(i18n.locale.value)
41-
assert.equal(head.value.htmlAttrs!.lang, 'en-US')
42-
return {
43-
i18n,
44-
head
45-
}
46-
}, [router, i18n])
55+
describe('identifierAttribute option', () => {
56+
it('should be worked', async () => {
57+
const i18n = createI18n({ legacy: false, locale: 'en' })
58+
const router = createRouter(i18n, {
59+
version: 4,
60+
locales: [
61+
{
62+
code: 'en',
63+
iso: 'en-US',
64+
dir: 'ltr'
65+
},
66+
{
67+
code: 'ja',
68+
iso: 'ja-JP'
69+
}
70+
],
71+
baseUrl: 'http://localhost:8080',
72+
routes: [
73+
{ path: '/', name: 'index', component: { template: '<div>index</div>' } },
74+
{ path: '/about', name: 'about', component: { template: '<div>About</div>' } },
75+
{ path: '/:pathMatch(.*)*', name: 'not-found', component: { template: '<div>Not Found</div>' } }
76+
],
77+
history: createMemoryHistory()
78+
})
79+
await router.push('/en/about')
4780

48-
await router.push('/ja')
49-
expect(vm.head).toMatchSnapshot(vm.i18n.locale.value)
50-
assert.equal(vm.head.htmlAttrs!.lang, 'ja-JP')
81+
const vm = useSetup(() => {
82+
const route = useRoute()
83+
const router = useRouter()
84+
const i18n = useI18n()
85+
const head = useLocaleHead({ addSeoAttributes: true, identifierAttribute: 'key', route, router, i18n })
86+
return {
87+
i18n,
88+
head
89+
}
90+
}, [router, i18n])
91+
92+
await router.push('/ja')
93+
for (const m of vm.head.meta || []) {
94+
expect(m).toHaveProperty('key')
95+
}
96+
})
5197
})
5298
})

packages/vue-i18n-routing/src/composables/head.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import type { Ref } from 'vue-demi'
2626
export function useLocaleHead({
2727
addDirAttribute = false,
2828
addSeoAttributes = false,
29+
identifierAttribute = 'hid',
2930
strategy = undefined,
3031
defaultLocale = undefined,
3132
route = useRoute(),
@@ -60,7 +61,7 @@ export function useLocaleHead({
6061
defaultLocale,
6162
strategy
6263
},
63-
[{ addDirAttribute, addSeoAttributes }]
64+
[{ addDirAttribute, addSeoAttributes, identifierAttribute }]
6465
) as I18nHeadMetaInfo
6566
}
6667

0 commit comments

Comments
 (0)