I am currently working on localization for my project.
I closely followed this guide https://prismic.io/blog/nextjs-i18n to achieve localization and while I have got the localization working, the routing has been affected since now my public folder is not accessible in my dev environment and PrismicPreview is not working.
My localization code is almost identically set up like the guide suggests so if anyone has encountered this before, I am all ears for a possible solution.
Hi @Phil ,
I´m currently using the PrismicPreview component from @prismicio/next and the package is up to date.
The PrismicPreview toolbar shows up, indicating that the preview is working but when I click the "Preview the page", I am directed to the base "not found" page given by NextJS in your codebase when scaffolding a project.
This behaviour tell me that likely the PrismicPreview component itself is not the problem but the way it is handling the new route setup.
Currently, my base route of localhost:3000 has a localization affix of /en-gb (which is not normally visible because it is the default locale) and /fr (which is visible when French is selected) so all my routes in french would be {localhost}/fr/{page} and all my routes in english would be {localhost}/{path}.
Is this commonly seen issue when using previews on locale prefixed routes?
OK, in that case, the route/link resolver is used to redirect to the correct page. So if there's a disconnect between the app folder structure and the link resolver, your previews will break down.
Can you show me the code for your link resolver and your preview component?
import {
FilledContentRelationshipField,
FilledLinkToMediaField,
FilledLinkToWebField,
LinkType,
} from '@prismicio/types';
import { PrismicLinkWithMeta } from './types/link';
import { RelatedDocument } from './prismic-types';
import { LinkField } from '@prismicio/client';
/**
* Optional base path, e.g. if everything prismic related is at `/prismic`
* set as `prismic/`, otherwise leave as empty string.
*/
const BASE_PATH = '';
/** The types we can link resolve, add any project specific types here */
export type LinkResolvable =
| (FilledLinkToWebField & {
_linkType?: string;
})
| (FilledLinkToMediaField & {
_linkType?: string;
})
| (FilledContentRelationshipField & {
_linkType?: string;
})
| PrismicLinkWithMeta
| LinkField
| null;
/** Possible values for normalized Prismic links */
export type LinkType = keyof typeof LinkType;
/** Normalize different representation of links in Prismic into one type */
export type NormalizedLink = {
/** Prismic returns this as either link_type or _linkType */
linkType?: LinkType | string;
uid?: string;
/** This is the document type, e.g. "frontpage", "page", "article" */
type?: string;
url?: string;
locale?: string;
};
/**
* When adding links via the Prismi UI, it's possible to paste in relative links (e.g. `/my-page`).
* In those cases the UI will append `https://` in front, so we end up with `https:///my-page`.
*
* @param url Possible url from the Prismic UI
* @returns Url with protocol stripped
*/
function fixRelative(url?: string): string {
if (!url) {
return '/';
}
const lowered = url.toLocaleLowerCase();
// Prismic UI will allow OR add https:// for relative links in their UI
if (lowered.startsWith('https:///')) {
return url.substring('https://'.length);
}
if (lowered.startsWith('http:///')) {
return url.substring('http://'.length);
}
return url;
}
/**
* Resolves a link to content based on its type.
*
* @param type Name of the content type in Prismic
* @param uid UID of content
* @param localeAsString Locale of content
* @returns Resolved link to the content based on input
*/
export function linkResolverByType(
type?: string,
uid?: string,
lang?: string
): string {
const localeHref = `${lang}${BASE_PATH}`;
switch (type) {
case 'frontpage':
case 'layout':
return localeHref;
default:
}
if (uid) {
return `${localeHref}${uid}`;
}
return "/";
}
/**
* When linking between content there are two possible ways Prismic represents it:
* - As link in RichText content
* - As link in "Linked Content" UI element
* This handles both types.
*
* @param link Normalized link to resolve
* @returns Resolved link to the content based on its link object
*/
export function linkResolverByLink(
link: NormalizedLink
): string {
if (!link.linkType) {
return '/';
}
// Possible values for link_type
if (
['Media', 'Web', 'File', 'Image', 'Document'].indexOf(
link.linkType
) >= 0
) {
return fixRelative(link.url);
}
// Possible values for _linkType
if (
[
'Link.media',
'Link.web',
'Link.file',
'Link.image',
'Link.Document'
].indexOf(link.linkType) >= 0
) {
return fixRelative(link.url);
}
return '/';
}
/**
* Checks the shape of the document to link resolve to and creates a link to it.
*
* @param doc Prismic document to resolve a link to
* @returns Link to document
*/
export function linkResolver(
doc?: LinkResolvable
): string {
if (!doc || typeof doc !== 'object') {
return '/';
}
// Preview and content relationship links
if ('link_type' in doc && 'uid' in doc) {
return linkResolverByLink({
linkType: doc.link_type,
uid: doc.uid,
type: doc.type,
url: doc.url,
locale: doc.lang,
});
}
// Media and Web links
if ('url' in doc) {
return linkResolverByLink({
linkType: doc.link_type,
url: doc.url,
});
}
return '/';
}
/**
* Tries to resolve a link to a related document that comes
* from `_meta.alternateLanguages`
* @param doc Related prismic document.
* @returns Link to document if able to resolve, otherwise `/`.
*/
export function linkResolverByRelatedDocument(
doc?: RelatedDocument
) {
if (!doc || !doc.uid) {
return '/';
}
return linkResolverByType(
doc.type,
doc.uid,
doc.lang
);
}
My PrismicPreview componentis imported from the v1.5.0 of the "@prismicio/next" module and is used in my layout.tsx like this:
I have figured out a solution to this problem and it is very simple.
In this guide, you'll have a [lang] folder and if you want to have previews available, you'll have an api folder.
Since localization will be appended to your base route (/ if it is your default locale and in my case, /fr since french is one of my chosen locales), you´ll want to move the api folder to the [lang] so instead of http://localhost:3000/api/preview, you'll get http://localhost:3000/fr/api/preview.
This simple fix solved my problem so this ticket can be closed.