hozana / next-translate-routes

Flexible and translated routes for Next.js without custom server
MIT License
115 stars 30 forks source link

Automatically make link rel=alternate for SEO? #29

Closed jeromeheissler closed 2 years ago

jeromeheissler commented 2 years ago

Can we use this plugin to automatically add this on each page based on _route.json :

<Head>
  <link rel="alternate" hrefLang="en" href="/en/about" />
  <link rel="alternate" hrefLang="fr" href="/fr/a-propos" />
</Head>

Maybe we can make a hook that takes the current page, search all rewrite for each language and return the Head tag with all alternate pages inside

NitrousBGC commented 2 years ago

I would like to know too ! It's so important for SEO and i can't manage to make it work with this..

draxx318 commented 2 years ago

Very important feature.

I managed to get it working using import { translatePath } from 'next-translate-routes/translateUrl'

But it doesn't work with page names with the "-" symbol in it (maybe even with other symbols).

Maybe this should be a separate issue?

NitrousBGC commented 2 years ago

Very important feature.

I managed to get it working using import { translatePath } from 'next-translate-routes/translateUrl'

But it doesn't work with page names with the "-" symbol in it (maybe even with other symbols).

Maybe this should be a separate issue?

Finally I changed package to make it work correctly.. You can check next-multilingual, they have all of this incorporated. (translations, translated routes, auto rel=alternate and rel=canonical,...) And for the creator of next-translate-routes, next-multilingual could be a good inspiration to focus more on SEO.

I hope we will find the ultimate package for translations including everything we need in one place.

gehaktmolen commented 2 years ago

I am doing the following to get alternative urls.

src/utils/localize-helpers.ts:

import type { NextRouter } from 'next/router';
import { translateUrl } from 'next-translate-routes';

export const formatSlug = (slug: string, locale?: string, defaultLocale?: string) => {
  return locale === defaultLocale ? `/${cleanSlug(slug)}` : `/${locale}/${cleanSlug(slug)}`.replace(/\/+$/, '');
}

export const cleanSlug = (slug: string) => slug.replace(/^\/|\/$/g, '');

/**
 * Translate our path, and return a complete translated URL.
 * Todo: 'next-translate-routes' doesn't provide a way to fetch the translated URL with locale prefixed?
 * @param router NextRouter
 * @param translateLocale The locale that we want to translate to.
 * @param format Decide if you want to add slashes and locale for a complete path.
 */
export const translatePath = (router: NextRouter, translateLocale?: string, format: boolean = true) => {
  const locale = translateLocale || router.locale;
  const slug = translateUrl(router, locale).pathname || '';
  return format
    ? formatSlug(slug, locale, router.defaultLocale)
    : cleanSlug(slug);
};

/**
 * Return an array of objects containing all translations of a route.
 * @param router NextRouter
 */
export const getLocalizedPaths = (router: NextRouter) => {
  return router.locales?.map((locale: string) => ({
    locale,
    path: `${translatePath(router, locale)}`,
  })) || [];
};

export const getLocalizedSlugs = (router: NextRouter) => {
  return router.locales?.map((locale: string) => ({
    locale,
    slug: `${translatePath(router, locale, false)}`,
  })) || [];
};

src/pages/_app.tsx:

...
import { useRouter } from 'next/router';
import { DefaultSeo } from 'next-seo';
import withTranslateRoutes, { translateUrl } from 'next-translate-routes';
import { getLocalizedPaths, translatePath } from '../utils/localize-helpers';
...
function MyApp() {
  const router = useRouter();
  const url = `${process.env.PROJECT_URL?.replace(/\/+$/, '')}`;

  const languageAlternatives = getLocalizedPaths(router).map((path) => ({
    hrefLang: path.locale,
    href: `${url}${path.path}`,
  }));
  languageAlternatives.push({ hrefLang: 'x-default', href: `${url}${translatePath(router)}` });

  return (
     <DefaultSeo
            {...SEO}
            canonical={`${url}${translatePath(router)}`}
            languageAlternates={languageAlternatives.map((locale) => ({
              hrefLang: locale.hrefLang,
              href: locale.href,
            }))}
          />
  )
}
cvolant commented 2 years ago

v1.9.0 is out, with two new helpers, fileUrlToUrl and urlToFileUrl. The docs now suggests a piece of code, quite similar to the above, to add alternate links. It seemed better to me to leave it like this, to avoid stepping out of next-transate-routes scope, and so that everyone can tweak it the way he want, using or not a dedicated package like next-seo. Feel free to reopen this issue if it is not satisfying.