Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

Dynamic Link, useRouter and usePathname locales #586

Closed
awinogrodzki opened this issue Oct 28, 2023 · 4 comments
Closed

Dynamic Link, useRouter and usePathname locales #586

awinogrodzki opened this issue Oct 28, 2023 · 4 comments
Labels
enhancement New feature or request unconfirmed Needs triage.

Comments

@awinogrodzki
Copy link

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

I have recently upgraded to 3.0.0-rc.6. There is one issue I am having in regards to this upgrade.

import {
  createLocalizedPathnamesNavigation,
  Pathnames
} from 'next-intl/navigation';
 
export const locales = ['en', 'de'] as const;
 
// The `pathnames` object holds pairs of internal
// and external paths, separated by locale.
export const pathnames = {
  // If all locales use the same pathname, a
  // single external path can be provided.
  '/': '/',
  '/blog': '/blog',
 
  // If locales use different paths, you can
  // specify each external path per locale.
  '/about': {
    en: '/about',
    de: '/ueber-uns'
  },
 
  // Dynamic params are supported via square brackets
  '/news/[articleSlug]-[articleId]': {
    en: '/news/[articleSlug]-[articleId]',
    de: '/neuigkeiten/[articleSlug]-[articleId]'
  },
 
  // Also (optional) catch-all segments are supported
  '/categories/[...slug]': {
    en: '/categories/[...slug]',
    de: '/kategorien/[...slug]'
  }
} satisfies Pathnames<typeof locales>;
 
export const {Link, redirect, usePathname, useRouter, getPathname} =
  createLocalizedPathnamesNavigation({locales, pathnames});

My app features locales dynamic per user. User can configure the set of languages the app supports.

createLocalizedPathnamesNavigation requires locales to be known at build time, the same for the whole app.

Describe the solution you'd like

Ideally, I would use internal next/navigation library features instead of decorated ones

Describe alternatives you've considered

I am still trying to figure out how I can create those components/hooks dynamically and it's a pain. Probably I would have to share them using React Context, which is quite painful.

@awinogrodzki awinogrodzki added enhancement New feature or request unconfirmed Needs triage. labels Oct 28, 2023
@awinogrodzki
Copy link
Author

Here's how I construct intl middleware:

export const handleI18nRouting = (client?: Client) =>
  createIntlMiddleware({
    locales:
      client?.settings && isFeatureEnabled(client.settings, Feature.Translation)
        ? getFeatureOption(client.settings, Feature.Translation, 'locales', locales)
        : locales,
    defaultLocale:
      client?.settings && isFeatureEnabled(client.settings, Feature.Translation)
        ? getFeatureOption(client.settings, Feature.Translation, 'defaultLocale', defaultLocale)
        : defaultLocale,
    localeDetection: client?.settings
      ? isFeatureEnabled(client.settings, Feature.Translation)
      : false,
  });

@awinogrodzki
Copy link
Author

awinogrodzki commented Oct 28, 2023

Here's what I've come up so far with 3.0.0-rc6

type LocalizedNavigation = ReturnType<typeof createLocalizedPathnamesNavigation<any, any>>;

interface PageRouterContextValue {
  navigation: LocalizedNavigation;
}

const PageRouterContext = createContext<PageRouterContextValue>({
  get navigation(): LocalizedNavigation {
    throw new Error('Context used outside provider');
  },
});

interface PageRouterProviderProps {
  children: React.ReactNode;
}

export function PageRouterProvider({ children }: PageRouterProviderProps) {
  const { settings, isFeatureEnabled, getFeatureOption } = useSettings();
  const navigation = useMemo(
    () =>
      createLocalizedPathnamesNavigation({
        locales: isFeatureEnabled(Feature.Translation)
          ? getFeatureOption(Feature.Translation, 'locales', locales)
          : locales,
        pathnames: {},
      }),
    [settings]
  );
  return (
    <PageRouterContext.Provider value={{ navigation: navigation as unknown as LocalizedNavigation }}>
      {children}
    </PageRouterContext.Provider>
  );
}

@aXenDeveloper
Copy link

aXenDeveloper commented Nov 3, 2023

You can import json file into createLocalizedPathnamesNavigation.
Something like this:

import configs from '~/config.json';

import { getRequestConfig } from 'next-intl/server';
import { createSharedPathnamesNavigation } from 'next-intl/navigation';

export default getRequestConfig(async ({ locale }) => {
  const messagesFormApps = await Promise.all(
    configs.applications.map(async app => {
      return {
        ...(await import(`~/langs/${locale}/${app}.json`)).default
      };
    })
  );

  return {
    messages: {
      ...messagesFormApps.reduce((acc, messages) => ({ ...acc, ...messages }), {})
    },
    timeZone: 'UTC'
  };
});

export const { Link, redirect, usePathname, useRouter } = createSharedPathnamesNavigation({
  locales: configs.languages.locales.filter(locale => locale.enabled).map(locale => locale.key)
});

@amannn
Copy link
Owner

amannn commented Nov 3, 2023

createLocalizedPathnamesNavigation is really about providing static type safety for the pathnames that are available to your application. Providing the resulting APIs via context doesn't seem right to me.

How many locales does your app handle? Any chance you can create the navigation APIs in the outer module scope with all supported locales and restrict them within the app to the sub-set that the user supports?

I'll move this to a discussion since this seems to be more of a usage question.

Repository owner locked and limited conversation to collaborators Nov 3, 2023
@amannn amannn converted this issue into discussion #597 Nov 3, 2023

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
enhancement New feature or request unconfirmed Needs triage.
Projects
None yet
Development

No branches or pull requests

3 participants