facebook / docusaurus

Easy to maintain open source documentation websites.
https://docusaurus.io
MIT License
56.38k stars 8.46k forks source link

i18n no defaultLocale fallback handling for single-domain-deployment strategy #4723

Open TomPeirs opened 3 years ago

TomPeirs commented 3 years ago

πŸ› Bug Report

There seems to be no fallback handling to the defaultLocale.

When I change with the localeDropdown to French (fr), my baseURL is appended with the locale. And will look like below https://docusaurus.io/fr/docs/i18n/tutorial However when I replace the french locale with my default locale (in my case: en) it will return a page not found. http://localhost:3000/en/docs/intro How can I make the defaultLocale accessible from the URL as the current 'strategy' is to strip the defaultlocale from the URL.

I think this is an important Bug because when starting to use Docusaurus V2 early we shipped some 'stable' URLs to production, and these URLs need to remain stable, meaning we have the locale always appended after the BaseURL. (also for default english).

What would be the suggestion? (to me it seems odd I would need to use the multi domain strategy and start configuring CDNs just to get this working)

To Reproduce

  1. Configure the sites locales i18n: { defaultLocale: 'en', locales: ['en', 'de'], },
  2. Write your translations (.. create i18n folder, with the locale folder, etc..)
  3. Build the application npm run build using the https://docusaurus.io/docs/i18n/tutorial#single-domain-deployment single domain deployment strategy

Expected behavior

I would expect that the application is accessible with the default locale prefix in the URL. Even better would be if you do not define the locale it all, that the application falls back to the defaultLocale if the document is available. e.g. https://docusaurus.io/it/docs/i18n/tutorial should fall back to https://docusaurus.io/docs/i18n/tutorial in case IT (Italian) is not defined as a locale.

Actual Behavior

Currently you see a Page Not Found forward. image

Your Environment

slorber commented 3 years ago

Hi @TomPeirs

This is something I actually plan to add, just wanted to see if someone come from a need for this and could help design the feature :)

In my opinion, it make sense for most users to have the default/en locale to not have a baseurl prefix by default, as most users already have an English Docusaurus sites with existing URLs (not using /en/ baseurl) and by default those URLs should continue working.

So my idea was to allow configuring the baseUrl for each locale independently, but use convenient default for most users.

For your use-case, as you don't want baseUrl: '/' for English, would the following API make sense?

module.exports = {
  i18n: {
    defaultLocale: 'en',
    locales: ['en', 'fr'],
    localeConfigs: {
      en: {
        baseUrl: '/en/'
      },
    },
  },
};

Now, /en/ and /fr/ exist, but there's nothing anymore at the root /. What do you expect Docusaurus to do if the user is browsing that root domain URL? Showing a 404 does not look like a good idea.

Note Docusaurus can only build static assets, and so, only do client-side redirects using JavaScript. And it's better to redirect using server-side redirects, but each host platform has a different way to configure this.

to me it seems odd I would need to use the multi domain strategy and start configuring CDNs just to get this working

Somehow, you could already solve your problem by running something like docusaurus build --locale en --out-dir build/en, this is basically what Docusaurus does behind the scene, nothing fancy. Building all locales at once is just "shortcut" to make this more convenient than running one cli command for each locale, but really it is the same in the end.

Even better would be if you do not define the locale it all, that the application falls back to the defaultLocale if the document is available. e.g. https://docusaurus.io/it/docs/i18n/tutorial should fall back to https://docusaurus.io/docs/i18n/tutorial in case IT (Italian) is not defined as a locale.

Docusaurus can only build a folder of static files. It's not clear to me what exactly is a "fallback" for you and how we should built this technically (ie what should the /build folder look like exactly?). I suspect you mean "redirect", but this is a server-side feature, and is specific to the host solution you are using.

Note: some popular server-side solutions like Github Pages are quite limited: it's not possible to perform a server-side redirect here for example. And if we build something, we definitively want this to work in all Jamstack hosting solutions, including Github Pages, or this would be confusing for many users.

If you have a clear idea of what you want and think it is technically possible, I'd suggest creating a POC by hand-writing some html files and deploying those to Github Pages so that I understand better your suggestion

In my opinion, the role of Docusaurus is only to build a folder of static assets. It is your responsibility to handle the rest, including configuring your host correctly for fallbacks/redirects, adding performant caching headers, rewrite URLs etc... We can only help by documenting this, but it's hard to be exhaustive

TomPeirs commented 3 years ago

Hey @slorber , Thank you for providing these insights.

Concerning

module.exports = {
  i18n: {
    defaultLocale: 'en',
    locales: ['en', 'fr'],
    localeConfigs: {
      en: {
        baseUrl: '/en/'
      },
    },
  },
};

For my particular use-case not having anything at the root would be fine we already handle this on proxy-level by forwarding to the /en in case someone browses the root. it would be great to be able to configure the localeConfigs as you porpose. But I guess your proposal is not available in Alpha-75 right? As I tried to compile localeConfigs as mentioned but this was not working.

This results in the following Error: These field(s) ["i18n,localeConfigs,en,baseUrl",] are not recognized in docusaurus.config.js. If you still want these fields to be in your configuration, put them in the 'customFields' attribute.

Somehow, you could already solve your problem by running something like docusaurus build --locale en --out-dir build/en, this is basically what Docusaurus does behind the scene, nothing fancy. Building all locales at once is just "shortcut" to make this more convenient than running one cli command for each locale, but really it is the same in the end.

This is also a good idea. I tried this out and did not get it working right away. I assume I have to duplicate my docusaurus.config.js file in order to modify the baseUrl to :/en/ or /de/ by passing --config to the CLI because currently I get the following: image

(I'll try it out this afternoon and update this ticket)

Docusaurus can only build a folder of static files. It's not clear to me what exactly is a "fallback" for you and how we should built this technically (ie what should the /build folder look like exactly?). I suspect you mean "redirect", but this is a server-side feature, and is specific to the host solution you are using.

I agree, you are right.

slorber commented 3 years ago

it would be great to be able to configure the localeConfigs as you porpose. But I guess your proposal is not available in Alpha-75 right? As I tried to compile localeConfigs as mentioned but this was not working.

No it is not added yet, but will do that, as I planned to add it anyway

I assume I have to duplicate my docusaurus.config.js file in order to modify the baseUrl to :/en/ or /de/ by passing --config to the CLI because currently I get the following:

Temporarily you can pass a baseurl by using nodejs env variables in your config file:

baseUrl: process.env.BASE_URL

And run this:

BASE_URL='/en/' docusaurus build --locale en --out-dir build/en
BASE_URL='/it/' docusaurus build --locale it --out-dir build/it
BASE_URL='/de/' docusaurus build --locale de --out-dir build/de

When using the --locale option, by default we don't add the baseurl automatically, as it does not make sense for subdomain deployments to be en.myDomain.com/en or fr.myDomain.com/fr

TomPeirs commented 3 years ago

Thank you, I had to slightly modify this to work with nodejs env variables.

First I installed cross-env.

  "devDependencies": {
    "cross-env": "^7.0.3"
  }

Then I modified the scripts: "build_german": "cross-env BASE_URL='/de/' docusaurus build --locale de --out-dir build/de "

Without cross-env I couldn't get it to work. I realized setting nodejs environment variables is windows is different.

Just leaving this here

HOWEVER, the proposed solution actually does not work @slorber yes I do have /en part of the URL now, but switching languages is broken The reason I think is because somehow the language switcher appends the locale rather then switching it. I show it in a video:

2021-05-04_13h20_25

slorber commented 3 years ago

Yes, this is somehow expected, as the drop-down need to be able to know all the localized urls πŸ˜… you would also need to create your own drop-down of hard-coded links for this to work (no navbar type + list of link items)

This is a temporary workaround, as my api proposal would solve this.

Le mar. 4 mai 2021 Γ  13:21, Tom Peirs @.***> a Γ©crit :

Thank you, I had to slightly modify this to work with nodejs env variables.

First I installed cross-env.

"devDependencies": { "cross-env": "^7.0.3" }

Then I modified the scripts: "build_german": "cross-env BASE_URL='/de/' docusaurus build --locale de --out-dir build/de "

Without cross-env I couldn't get it to work. I realized setting nodejs environment variables is windows is different.

Just leaving this here

HOWEVER, the proposed solution actually does not work @slorber https://github.com/slorber yes I do have /en part of the URL now, but switching languages is broken The reason I think is because somehow the language switcher appends the locale rather then switching it. I show it in a video:

[image: 2021-05-04_13h20_25] https://user-images.githubusercontent.com/68061801/116996356-93a7e000-acdb-11eb-8dfd-b79325ebae74.gif

β€” You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/facebook/docusaurus/issues/4723#issuecomment-831867183, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFW6PV3RVBCXDXR5DGAVRDTL7KERANCNFSM44CEXYOQ .

TomPeirs commented 3 years ago

oke thank you @slorber ,

In that case I will move away for this for a little bit. Any chance to give me an estimation when you will merge and publish this and will it be in Alpha 76?

TomPeirs commented 3 years ago

@slorber , I'm not so familiar with the core of docsuarus yet so I was affraid to open a PR (because my change would only work for this use case).I wasn't sure how I would properly read and configure parameters from the docusaurus.config.js.

Hence, for my use-case where I deploy to build/en/ and build/de/ and have nothing on root, I swizzled the LocaleDropDownNavbarItem. I imported useAlternatePageUtils from a local copy. In the useAlternatePageUtils I then slightly modified the baseUrlocalized constant as well as the getLocalizedBaseUrl method.

 const baseUrlUnlocalized =
    currentLocale === defaultLocale
      ? baseUrl
      : baseUrl.replace(`/${currentLocale}/`, `/${defaultLocale}/`);

  const pathnameSuffix = pathname.replace(baseUrl, '');

  function getLocalizedBaseUrl(locale: string) {
    return locale === defaultLocale
      ? `${baseUrlUnlocalized}`
      : `${baseUrlUnlocalized.replace(`/${defaultLocale}/`,`/${locale}/`)}`;

Like this the localeDropdown is working as expected for me. I'm sure you have a better technical solution with your API proposal, so I will be happily to test it for you need someone to test it.

slorber commented 3 years ago

Thanks

I'll tell you when I have a version to test with these features

Is your site open-source so that I can test on your site directly?

TomPeirs commented 3 years ago

Thanks

I'll tell you when I have a version to test with these features

Is your site open-source so that I can test on your site directly?

It's not public, But on Friday I will create a vercel deployment for you with a version where I block out sensitive data.

TomPeirs commented 3 years ago

@slorber I think this ticket relates heavily to https://github.com/facebook/docusaurus/issues/3285 I think the problems described here will be fixed with the RFC.

Do you agree to close this?

slorber commented 3 years ago

Not exactly the same, this issue is about i18n locale configuration, not docs version configuration (both should allow to configure the path)

Still in my todo list, which unfortunately is quite long πŸ˜…

xiaosongxiaosong commented 2 years ago

Hi, @slorber, i have create a pr https://github.com/facebook/docusaurus/pull/6731 for support this feature, I'm glad you could point it out for me if there's anything I've missed.

Hi @TomPeirs

This is something I actually plan to add, just wanted to see if someone come from a need for this and could help design the feature :)

In my opinion, it make sense for most users to have the default/en locale to not have a baseurl prefix by default, as most users already have an English Docusaurus sites with existing URLs (not using /en/ baseurl) and by default those URLs should continue working.

So my idea was to allow configuring the baseUrl for each locale independently, but use convenient default for most users.

For your use-case, as you don't want baseUrl: '/' for English, would the following API make sense?

module.exports = {
  i18n: {
    defaultLocale: 'en',
    locales: ['en', 'fr'],
    localeConfigs: {
      en: {
        baseUrl: '/en/'
      },
    },
  },
};

Now, /en/ and /fr/ exist, but there's nothing anymore at the root /. What do you expect Docusaurus to do if the user is browsing that root domain URL? Showing a 404 does not look like a good idea.

Note Docusaurus can only build static assets, and so, only do client-side redirects using JavaScript. And it's better to redirect using server-side redirects, but each host platform has a different way to configure this.

to me it seems odd I would need to use the multi domain strategy and start configuring CDNs just to get this working

Somehow, you could already solve your problem by running something like docusaurus build --locale en --out-dir build/en, this is basically what Docusaurus does behind the scene, nothing fancy. Building all locales at once is just "shortcut" to make this more convenient than running one cli command for each locale, but really it is the same in the end.

Even better would be if you do not define the locale it all, that the application falls back to the defaultLocale if the document is available. e.g. docusaurus.io/it/docs/i18n/tutorial should fall back to docusaurus.io/docs/i18n/tutorial in case IT (Italian) is not defined as a locale.

Docusaurus can only build a folder of static files. It's not clear to me what exactly is a "fallback" for you and how we should built this technically (ie what should the /build folder look like exactly?). I suspect you mean "redirect", but this is a server-side feature, and is specific to the host solution you are using.

Note: some popular server-side solutions like Github Pages are quite limited: it's not possible to perform a server-side redirect here for example. And if we build something, we definitively want this to work in all Jamstack hosting solutions, including Github Pages, or this would be confusing for many users.

If you have a clear idea of what you want and think it is technically possible, I'd suggest creating a POC by hand-writing some html files and deploying those to Github Pages so that I understand better your suggestion

In my opinion, the role of Docusaurus is only to build a folder of static assets. It is your responsibility to handle the rest, including configuring your host correctly for fallbacks/redirects, adding performant caching headers, rewrite URLs etc... We can only help by documenting this, but it's hard to be exhaustive

ahtremblay commented 2 years ago

I think it is more intuitive to simply make defaultLocale optional. For instance:

module.exports = {
  i18n: {
    locales: ['en', 'fr'],
  },
};

would output en to /en/ and fr to /fr/ (leaving root empty), while:

module.exports = {
  i18n: {
    defaultLocale: 'en',
    locales: ['en', 'fr'],
  },
};

would output en to / and fr to /fr/.

arnaud4d commented 2 years ago

I also have the issue to support external links to docusaurus v1 site: they all include '/en/', and no longer work in v2 :-(. Moreover, translators need to know that they have to add their languages in the urls because they don't see /en/ in them. I would like to have a simple 'defaultLocaleInUrl' option.

bclabs-kylian commented 2 years ago

This is so needed imo. Will be waiting for the feature release

Jwaegebaert commented 2 years ago

Is there an update regarding this issue? I would love to have this feature within docusaurus, or the option to configure a custom baseUrl would also be nice.

wiktorsikora commented 1 year ago

I am also interested in this feature.