Repository: garmeeh/next-seo
Pull request #115 (2019-10-27 17:24:47)

Multiple alternate languages
Closes https://github.com/garmeeh/next-seo/issues/114

garmeeh: Hey @petertulala, thanks for the PR. The tests are currently failing on this if you could take a look. 

😞 Travis stopped showing up here so will need to take a look at why. 
petertulala: @garmeeh Sorry for the delay. I've fixed the failing tests. Please have a look.
garmeeh: @all-contributors please add @petertulala for code, test
allcontributors[bot]: @garmeeh 

I've put up [a pull request](https://github.com/garmeeh/next-seo/pull/118) to add @petertulala! :tada:

Patch:
diff --git a/src/meta/buildTags.tsx b/src/meta/buildTags.tsx
index 5214607..591695d 100644
--- a/src/meta/buildTags.tsx
+++ b/src/meta/buildTags.tsx
@@ -77,15 +77,17 @@ const buildTags = (config: BuildTagsParams) => {
     );
   }
 
-  if (config.languageAlternate) {
-    tagsToRender.push(
-      <link
-        rel="alternate"
-        key="languageAlternate"
-        hrefLang={config.languageAlternate.hrefLang}
-        href={config.languageAlternate.href}
-      />,
-    );
+  if (config.languageAlternates && config.languageAlternates.length > 0) {
+    config.languageAlternates.forEach(languageAlternate => {
+      tagsToRender.push(
+        <link
+          rel="alternate"
+          key={`languageAlternate-${languageAlternate.hrefLang}`}
+          hrefLang={languageAlternate.hrefLang}
+          href={languageAlternate.href}
+        />,
+      );
+    });
   }
 
   if (config.twitter) {
diff --git a/src/meta/defaultSEO.tsx b/src/meta/defaultSEO.tsx
index c181cf9..68d7992 100644
--- a/src/meta/defaultSEO.tsx
+++ b/src/meta/defaultSEO.tsx
@@ -21,7 +21,7 @@ export default class extends Component<DefaultSeoProps, {}> {
       defaultOpenGraphVideoWidth,
       defaultOpenGraphVideoHeight,
       mobileAlternate,
-      languageAlternate,
+      languageAlternates,
     } = this.props;
 
     return (
@@ -41,7 +41,7 @@ export default class extends Component<DefaultSeoProps, {}> {
           defaultOpenGraphVideoWidth,
           defaultOpenGraphVideoHeight,
           mobileAlternate,
-          languageAlternate,
+          languageAlternates,
         })}
       </Head>
     );
diff --git a/src/meta/nextSEO.tsx b/src/meta/nextSEO.tsx
index f2e2c04..ee5a4e1 100644
--- a/src/meta/nextSEO.tsx
+++ b/src/meta/nextSEO.tsx
@@ -16,7 +16,7 @@ export default class extends Component<NextSeoProps, {}> {
       additionalMetaTags,
       titleTemplate,
       mobileAlternate,
-      languageAlternate,
+      languageAlternates,
     } = this.props;
 
     return (
@@ -32,7 +32,7 @@ export default class extends Component<NextSeoProps, {}> {
           twitter,
           titleTemplate,
           mobileAlternate,
-          languageAlternate,
+          languageAlternates,
         })}
       </Head>
     );
diff --git a/src/types.ts b/src/types.ts
index 644ac0e..5dd57b2 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -107,7 +107,7 @@ export interface NextSeoProps {
   description?: string;
   canonical?: string;
   mobileAlternate?: MobileAlternate;
-  languageAlternate?: LanguageAlternate;
+  languageAlternates?: ReadonlyArray<LanguageAlternate>;
   openGraph?: OpenGraph;
   facebook?: { appId: string };
   twitter?: Twitter;


Test patch:
diff --git a/src/meta/__tests__/__snapshots__/buildTags.spec.tsx.snap b/src/meta/__tests__/__snapshots__/buildTags.spec.tsx.snap
index d3606e4..c0cbd00 100644
--- a/src/meta/__tests__/__snapshots__/buildTags.spec.tsx.snap
+++ b/src/meta/__tests__/__snapshots__/buildTags.spec.tsx.snap
@@ -483,6 +483,11 @@ exports[`renders correctly 1`] = `
     hreflang="de-AT"
     rel="alternate"
   />
+  <link
+    href="https://www.canonical.ie/sk"
+    hreflang="sk-SK"
+    rel="alternate"
+  />
   <meta
     content="summary_large_image"
     name="twitter:card"
diff --git a/src/meta/__tests__/buildTags.spec.tsx b/src/meta/__tests__/buildTags.spec.tsx
index 5be9f92..485aff5 100644
--- a/src/meta/__tests__/buildTags.spec.tsx
+++ b/src/meta/__tests__/buildTags.spec.tsx
@@ -16,10 +16,16 @@ const SEO: BuildTagsParams = {
     media: 'only screen and (max-width: 640px)',
     href: 'https://m.canonical.ie',
   },
-  languageAlternate: {
-    hrefLang: 'de-AT',
-    href: 'https://www.canonical.ie/de',
-  },
+  languageAlternates: [
+    {
+      hrefLang: 'de-AT',
+      href: 'https://www.canonical.ie/de',
+    },
+    {
+      hrefLang: 'sk-SK',
+      href: 'https://www.canonical.ie/sk',
+    },
+  ],
   openGraph: {
     type: 'website',
     locale: 'en_IE',
@@ -157,23 +163,28 @@ it('returns full array for default seo object', () => {
     `link[media="${SEO.mobileAlternate.media}"]`,
   );
 
-  const languageAlternateTag = container.querySelectorAll(
+  expect(Array.from(mobileAlternateTag).length).toBe(1);
+  expect(Array.from(mobileAlternateHref).length).toBe(1);
+  expect(Array.from(mobileAlternateMedia).length).toBe(1);
+
+  const languageAlternatesTags = container.querySelectorAll(
     'link[rel="alternate"][hrefLang]',
   );
-  const languageAlternateHref = container.querySelectorAll(
-    `link[href="${SEO.languageAlternate.href}"]`,
-  );
-  const languageAlternateHrefLang = container.querySelectorAll(
-    `link[hrefLang="${SEO.languageAlternate.hrefLang}"]`,
+  expect(Array.from(languageAlternatesTags).length).toBe(
+    SEO.languageAlternates.length,
   );
 
-  expect(Array.from(mobileAlternateTag).length).toBe(1);
-  expect(Array.from(mobileAlternateHref).length).toBe(1);
-  expect(Array.from(mobileAlternateMedia).length).toBe(1);
+  SEO.languageAlternates.forEach((languageAlternate, idx) => {
+    const languageAlternateHref = container.querySelectorAll(
+      `link[href="${SEO.languageAlternates[idx].href}"]`,
+    );
+    const languageAlternateHrefLang = container.querySelectorAll(
+      `link[hrefLang="${SEO.languageAlternates[idx].hrefLang}"]`,
+    );
 
-  expect(Array.from(languageAlternateTag).length).toBe(1);
-  expect(Array.from(languageAlternateHref).length).toBe(1);
-  expect(Array.from(languageAlternateHrefLang).length).toBe(1);
+    expect(Array.from(languageAlternateHref).length).toBe(1);
+    expect(Array.from(languageAlternateHrefLang).length).toBe(1);
+  });
 
   expect(title).toBeDefined();
   expect(Array.from(index).length).toBe(2);