Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for partially translated routes #990

Open
maxijonson opened this issue Apr 9, 2024 · 3 comments
Open

Add support for partially translated routes #990

maxijonson opened this issue Apr 9, 2024 · 3 comments
Labels
contributions welcome Good for people looking to contribute enhancement New feature or request

Comments

@maxijonson
Copy link

maxijonson commented Apr 9, 2024

Is your feature request related to a problem? Please describe.

We support 6 languages on our website: en, fr, es, pt, ja and ru. All pages are initially written in english, but not always in all of the other languages. This puts us in the following use-cases:

  • Any time we need to render links to partially translated, we need to conditionally check if the current locale is "eligible" to have it shown. In our particular case, defaulting to an english link is not an option (even if it's possible, we don't want that).
  • When working with localized pathnames, we also need to define a path for other languages, even though there are no pages for it (to satisfy types)
  • We haven't started development on alternate links yet, but I expect we'll have a similar issues for them, where we only want alternate links for languages that exist.

All of these are not blockers though, since there are workarounds to all of them. It's just repetitive to have to apply those workarounds every time we encounter one of those situations.

Describe the solution you'd like

It would be nice for next-intl to provide ways of working with partially translated pages:

  • For Link created with createLocalizedPathnamesNavigation or createSharedPathnamesNavigation, this could potentially be achieved with a prop like availableLocales. Alternatively, for createSharedPathnamesNavigation, it could use the pathnames to know if the page is translated (only when the languages are specified)
  • For pathnames passed to createLocalizedPathnamesNavigation, this could be achieved by allowing only some languages to be specified.
  • For alternate links, I didn't dive into this yet, so maybe there's a better solution, but looking at the pathnames of the middleware configuration could hint to which links are available in which locale. "/blog": "/blog" would mean it is available in all languages, while the following would mean it is available only in en, fr and es:
    "/about-us": {
        en: "/about-us",
        fr: "/a-propos-de-nous",
        es: "/about-us"
    }
    

Describe alternatives you've considered

Link

There are 2 alternatives. Either use conditional rendering:

import { useLocale, useTranslations } from "next-intl";
import { Link } from "@/src/i18n/navigation";

const Page = () => {
    const locale = useLocale();
    const t = useTranslations();

    return (
        <div>
            {/* ... */}
            {["en", "fr", "es"].includes(locale) && (
                <Link href="/about-us">{t("Footer.about_us")}</Link>
            )}
            {/* ... */}
        </div>
    )
};

or make a wrapper component that encapsulate the above logic:

import { useLocale, useTranslations } from "next-intl";
import { Link } from "@/src/i18n/navigation";

const LocalizedLink = ({ availableLocales, ...props }) => {
    const locale = useLocale();
    if (!availableLocales.includes(locale)) return null;

    return <Link {...props} />;
}

const Page = () => {
    const t = useTranslations();

    return (
        <div>
            {/* ... */}
            <LocalizedLink availableLocales={["en", "fr", "es"]} href="/about-us">
                {t("Footer.about_us")}
            </LocalizedLink>
            {/* ... */}
        </div>
    )
};

Pathnames

The solution is just to provide an arbitrary path (usually the en one)

const makePartiallyLocalizedPathname = (
  paths: {
    [key in Exclude<Language, "en">]?: string;
  } & { en: string },
): Record<Language, string> => {
  return {
    en: paths.en,
    fr: paths.fr ?? paths.en,
    es: paths.es ?? paths.en,
    pt: paths.pt ?? paths.en,
    ja: paths.ja ?? paths.en,
    ru: paths.ru ?? paths.en,
    ko: paths.ko ?? paths.en,
  };
};

export const pathnames = {
  "/about-us": makePartiallyLocalizedPathname({
    en: "/about-us",
    fr: "/a-propos-de-nous",
    es: "/about-us", // we could have omitted it, but it's just a hint for us that this is translated
  }),
} satisfies Pathnames<typeof languages>;

Alternate links

Again, we haven't looked into this yet, but prior to integrating next-intl, we were handling i18n manually (using the documented way by NextJS, which doesn't require any 3rd party lib). So the alternative would be to just turn off alternates from next-intl and create them by ourselves: (this isn't exactly how it's implemented, we have a couple helpers we built to help us, but that's the general idea of what's being done):

export const generateMetadata = async ({
  params: { locale },
}): Promise<Metadata> => {
  const canonical = (() => {
    switch (locale) {
      case "fr":
        return "/fr/a-propos-de-nous";
      case "es":
        return "/es/about-us";
      default:
        return "/about-us";
    }
  })();

return {
  canonical,
  languages: {
    "x-default": "/about-us",
    fr: "/fr/a-propos-de-nous",
    es: "/es/about-us",
    en: "/about-us",
  },
};

I've also seen the docs has a FAQ answer on customizing your own alternate links, but it's unclear at this time if this would suit us (since we haven't looked into it too far yet! 😛)

@maxijonson maxijonson added enhancement New feature or request unconfirmed Needs triage. labels Apr 9, 2024
@maxijonson
Copy link
Author

After finally digging into alternate links, it does indeed do what I thought it would: every path gets an alternate link for each locale. This is problematic in our case, because like I mentioned, some pages (like /blog) are not available in all of the configured locales. So an alternate link pointing to something like /ru/blog shouldn't exist. Same thing goes for blog posts (/blog/[slug] in our pathnames). Almost all of our posts are in a single language and when they're translated, they'll always have a different slug.

However, instead of going for my previous solution, which was to disable alternateLinks in the middleware and just generate them myself with generateMetadata, I came up with a middleware to help me. It uses some derived pathnames which doesn't necessarily define the path for all of the locales and removes the alternate links if their language doesn't appear in the pathname definition.

I also came up with a Link wrapper called LocalizedLink, a bit like I mentioned above, but I did make a couple modifications.

It's still in development though, so it hasn't been thoroughly tested yet, but if it ends up working well, I'll probably share how I've done it, in case other people are in a similar situation.

Copy link

This issue has been automatically closed because there was no recent activity and it was marked as unconfirmed. Note that issues are regularly checked and if they remain in unconfirmed state, they might miss information required to be actionable or are potentially out-of-scope. If you'd like to discuss this topic further, feel free to open a discussion instead.

@github-actions github-actions bot added the Stale label May 11, 2024
@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale May 11, 2024
@amannn amannn reopened this May 11, 2024
@amannn
Copy link
Owner

amannn commented May 11, 2024

The same issue has been discussed in #1009 and #955.

A potential solution is discussed in #1009 (reply in thread). In case someone is interested in implementing this, I'd be happy to review a PR!

@amannn amannn added contributions welcome Good for people looking to contribute and removed unconfirmed Needs triage. Stale labels May 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contributions welcome Good for people looking to contribute enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants