Repository: garmeeh/next-seo
Pull request #118 (2019-11-13 20:46:42)

docs: add petertulala as a contributor
Adds @petertulala as a contributor for code, test.

This was requested by garmeeh [in this comment](https://github.com/garmeeh/next-seo/pull/115#issuecomment-553594712)


Patch:
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 1e4183f..615f345 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -130,6 +130,16 @@
       "contributions": [
         "code"
       ]
+    },
+    {
+      "login": "petertulala",
+      "name": "Peter Tulala",
+      "avatar_url": "https://avatars1.githubusercontent.com/u/613623?v=4",
+      "profile": "https://github.com/petertulala",
+      "contributions": [
+        "code",
+        "test"
+      ]
     }
   ],
   "contributorsPerLine": 7
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 6c2c1bc..0c099a8 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -14,8 +14,9 @@ yarn install
 ```
 
 2. Make your modifications / additions
-3. Write / Update Tests. End to end tests are required for all changes and new features.
-4. Open pull request
+3. Update / Add Documentation
+4. Write / Update Tests. End to end tests are required for all changes and new features.
+5. Open pull request
 
 ## Working with next-seo
 
diff --git a/README.md b/README.md
index 0be8016..e16fcc9 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # Next SEO
 
-[![All Contributors](https://img.shields.io/badge/all_contributors-12-orange.svg?style=flat-square)](#contributors)
+[![All Contributors](https://img.shields.io/badge/all_contributors-13-orange.svg?style=flat-square)](#contributors)
 
 Next SEO is a plugin that makes managing your SEO easier in Next.js projects.
 
@@ -239,8 +239,7 @@ From now on all of your pages will have the defaults above applied.
 | `canonical`                        | string                  | Set the page canonical url                                                                                                                                                           |
 | `mobileAlternate.media`            | string                  | Set what screen size the mobile website should be served from                                                                                                                        |
 | `mobileAlternate.href`             | string                  | Set the mobile page alternate url                                                                                                                                                    |
-| `languageAlternate.hrefLang`       | string                  | Set the language of the alternate url                                                                                                                                                |
-| `languageAlternate.href`           | string                  | Set the alternate language page url                                                                                                                                                  |
+| `languageAlternate`                | array                   | Set the language of the alternate urls. Excepts object: `{ hrefLang: string, href: string }`                                                                                         |
 | `additionalMetaTags`               | array                   | Allows you to add a meta tag that is not documented here. [More Info](#additional-meta-tags)                                                                                         |
 | `twitter.cardType`                 | string                  | The card type, which will be one of `summary`, `summary_large_image`, `app`, or `player`                                                                                             |
 | `twitter.site`                     | string                  | @username for the website used in the card footer                                                                                                                                    |
@@ -1177,6 +1176,7 @@ Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds
     <td align="center"><a href="https://ermakov.io"><img src="https://avatars0.githubusercontent.com/u/301917?v=4" width="100px;" alt="Dmitry Ermakov"/><br /><sub><b>Dmitry Ermakov</b></sub></a><br /><a href="https://github.com/garmeeh/next-seo/commits?author=zetoke" title="Code">💻</a></td>
     <td align="center"><a href="https://github.com/duckranger"><img src="https://avatars0.githubusercontent.com/u/2087890?v=4" width="100px;" alt="Nimo Naamani"/><br /><sub><b>Nimo Naamani</b></sub></a><br /><a href="https://github.com/garmeeh/next-seo/commits?author=duckranger" title="Documentation">📖</a></td>
     <td align="center"><a href="https://github.com/calvinvoo2"><img src="https://avatars2.githubusercontent.com/u/12223423?v=4" width="100px;" alt="Calvin Ng Tjioe"/><br /><sub><b>Calvin Ng Tjioe</b></sub></a><br /><a href="https://github.com/garmeeh/next-seo/commits?author=calvinvoo2" title="Code">💻</a></td>
+    <td align="center"><a href="https://github.com/petertulala"><img src="https://avatars1.githubusercontent.com/u/613623?v=4" width="100px;" alt="Peter Tulala"/><br /><sub><b>Peter Tulala</b></sub></a><br /><a href="https://github.com/garmeeh/next-seo/commits?author=petertulala" title="Code">💻</a> <a href="https://github.com/garmeeh/next-seo/commits?author=petertulala" title="Tests">⚠️</a></td>
   </tr>
 </table>
 
diff --git a/pull_request_template.md b/pull_request_template.md
index a760432..e0febd0 100644
--- a/pull_request_template.md
+++ b/pull_request_template.md
@@ -2,6 +2,14 @@
 
 ---
 
-Please have a read of the Contributing Guide before submitting a pull request.
+Some things to help get a PR reviewed and merged faster:
+
+- Have you updated the documentation to go with your changes?
+- Have you written or updated unit tests?
+- Have you written an integration test in the test app supplied?
+
+The above are generally required on all PR's.
+
+Please have a read of the Contributing Guide for full details.
 
 https://github.com/garmeeh/next-seo/blob/master/CONTRIBUTING.md
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/e2e/next-seo.config.ts b/e2e/next-seo.config.ts
index efd8b4c..255efa7 100644
--- a/e2e/next-seo.config.ts
+++ b/e2e/next-seo.config.ts
@@ -11,10 +11,12 @@ const APP_DEFAULT_SEO: DefaultSeoProps = {
     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',
+    },
+  ],
   openGraph: {
     type: 'website',
     locale: 'en_IE',
diff --git a/e2e/pages/overridden.tsx b/e2e/pages/overridden.tsx
index c939099..87155e9 100644
--- a/e2e/pages/overridden.tsx
+++ b/e2e/pages/overridden.tsx
@@ -9,10 +9,12 @@ export default () => (
       title="Title B"
       description="Description B"
       canonical="https://www.canonical.ie/b"
-      languageAlternate={{
-        hrefLang: 'de-AT',
-        href: 'https://www.canonical.ie/de',
-      }}
+      languageAlternates={[
+        {
+          hrefLang: 'de-AT',
+          href: 'https://www.canonical.ie/de',
+        },
+      ]}
       mobileAlternate={{
         media: 'only screen and (max-width: 640px)',
         href: 'https://m.canonical.ie',
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);