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

How can I use nuxt-typed-router with @nuxtjs/i18n? #48

Closed
szulcus opened this issue Nov 4, 2022 · 42 comments · Fixed by #65
Closed

How can I use nuxt-typed-router with @nuxtjs/i18n? #48

szulcus opened this issue Nov 4, 2022 · 42 comments · Fixed by #65
Labels
enhancement New feature or request

Comments

@szulcus
Copy link

szulcus commented Nov 4, 2022

https://v8.i18n.nuxtjs.org/

@victorgarciaesgi
Copy link
Owner

Hi! What do you mean?

@victorgarciaesgi victorgarciaesgi added the question Further information is requested label Jan 19, 2023
@the94air
Copy link

the94air commented Jan 31, 2023

Hello, @victorgarciaesgi. I think they were referring to the ability of using localePath() and other methods of the nuxt-i18n module along with this library. As you can tell from their library usage, you have to wrap all path calls with a localePath method. Which gets in the way of making good use of the type safety your library provide.
The way it works, it adds more routes for each locale on the project for every page, which require adding some changes to
every route path and name. To return the correct path or route details for each page, there are composables that should be called over other vue-router methods. These methods are required to make the i18n functionality work over vue-router.
For example:

// Won't work 🚫
router.push({
  name: "article",
  query: { id: article.id },
);

// Works ✅ but type checking is lost
const localePath = useLocalePath();

router.push(
  localePath({
    name: "article",
    query: { id: article.id },
  })
);
<!-- Won't work 🚫 -->
<NuxtLink :to="{ name: 'article', query: { id: article.id } }">
  some article
</NuxtLink>

<!-- Works ✅ but type checking is lost -->
<NuxtLink
  :to="localePath({ name: 'article', query: { id: article.id } })"
>
  some article
</NuxtLink>

Is it possible that this library can be compatible with the nuxt-i18n module or is it something that has to be provided by them separately? Thank you!

@victorgarciaesgi
Copy link
Owner

Hi @the94air , thanks for a so detailed response!!
By your exemples, it seems like the best solution is to override the useLocalePath typings, it would not be hard.
The thing I cant to test is if I can't know the module is present without specifying an additional config option.

@the94air
Copy link

the94air commented Feb 1, 2023

@victorgarciaesgi Correct. Due to the limited access to nuxt configs from a nuxt module, there won't be a way to detect if the nuxt-i18n is being used. It most be provided as an option instead. Maybe adding a boolean i18n option could be convenient?

@victorgarciaesgi
Copy link
Owner

Just made a quick deep dive, I can lookup automatically for @nuxtjs/i18n module presence in the config

@victorgarciaesgi victorgarciaesgi added enhancement New feature or request and removed question Further information is requested labels Feb 1, 2023
@victorgarciaesgi
Copy link
Owner

@the94air Okay managed to add support for useLocalePath and useLocaleRoute without adding a i18n option.
It's 0 config and can also autocompletes your locales!

You can try it on v2.3.0-beta.0 ! I just need to write doc and tests for it 😁

@victorgarciaesgi victorgarciaesgi linked a pull request Feb 1, 2023 that will close this issue
@the94air
Copy link

the94air commented Feb 2, 2023

That's awesome @victorgarciaesgi. I'll test it and let you know 👍

@victorgarciaesgi
Copy link
Owner

No problem! Thanks for the provided details 🙏
Docs also updated!

@szulcus
Copy link
Author

szulcus commented Feb 2, 2023

Hi @victorgarciaesgi,
I am very happy that you added these changes. Is it possible to use your module by configuring @nuxtjs/i18n like this?
image

@victorgarciaesgi
Copy link
Owner

Hi! Hmm maybe it doesn't support this syntax, I will test and publish an update to catch all module declarations syntaxes

@szulcus
Copy link
Author

szulcus commented Feb 2, 2023

It would be great, thanks!

@victorgarciaesgi
Copy link
Owner

@szulcus Done on v2.3.1 !

@szulcus
Copy link
Author

szulcus commented Feb 3, 2023

@victorgarciaesgi could you take a look?
image
image
A similar situation is with router.push.

@victorgarciaesgi
Copy link
Owner

@szulcus yep types were not compatible, was tricky but managed to fixed.

Try v2.3.2

@szulcus
Copy link
Author

szulcus commented Feb 3, 2023

@victorgarciaesgi I still have that problem there 😕. If it helps, I can create a reproduction.

@victorgarciaesgi
Copy link
Owner

Oh weird didn't reproduce, yeah if you can it would help 😁

@victorgarciaesgi
Copy link
Owner

Ok comes from the fact you navigate by string path, fixed the bug.
But by the way there is no autocomplete yet for url paths, it will come in the next big update

@victorgarciaesgi
Copy link
Owner

To fix your type issue you have to navigate by name localePath({name: 'sign-up'})

@the94air
Copy link

the94air commented Feb 5, 2023

@victorgarciaesgi Thank you, I really appreciate your efforts in adding this feature. I have tested v2.3.3 and it's very close to the desired result. It does return the types being declared on the vue-router but with the i18n suffix included:

router.push(localePath({ name: "index___en" }));
router.push(localePath({ name: "index___fr" }));

So currently with the correct locale name, it returns this type error:

router.push(localePath({ name: "index" })); // Type '"index"' is not assignable to type 'RoutesNamesList | undefined'.

Although the right nuxt-i18n way of declaring path names has to be without their locale suffix. The RoutesNamesList type has to contain the route names without their locale suffix. index___en and index___fr for example will become index. the localePath() method will return the correct suffix based on the currently selected locale. Let me know if you have any questions 👍

@victorgarciaesgi
Copy link
Owner

Thanks again for the explanation @the94air! I will release the fix on a major version along with path navigation check because removing them could break some apps.

@victorgarciaesgi
Copy link
Owner

By the way, the 3.0.0-beta.0 version is available with the I18n changes!
https://github.com/victorgarciaesgi/nuxt-typed-router/releases/tag/v3.0.0-beta.0

@kerunix
Copy link

kerunix commented Feb 22, 2023

Great job on v3.0.0 so far but the typings are still broken when navigating by name instead of by path.

Currently, using the following :
"nuxt-typed-router": "3.0.0-beta.0"
"@nuxtjs/i18n": "^8.0.0-beta.7"

I have the following behaviour:

navigateTo(localePath('/account/auth/login')) // Will work
navigateTo(localePath({ name: 'account-auth-login' })) // Will raise a TS error

In my ./nuxt/typed-router/_paths.d.ts I can see that the generated paths are correct, but in ./nuxt/typed-router/_routes.d.ts I still have the ___en extension at the end of each route name in the RoutesNamesList union.

I'd be happy to provide any additional information if you want 👍

@victorgarciaesgi
Copy link
Owner

Hi @kerunix! Try v3.0.0-beta.7, I fixed a lot of bugs with path navigation :D
Tell me if the problem with the __en extension is still here

@victorgarciaesgi
Copy link
Owner

Should be nearly ready, I need to write more tests and docs for it!

@kerunix
Copy link

kerunix commented Feb 22, 2023

@victorgarciaesgi Thanks for the quick response but I just tried updrading to v3.0.0-beta.7 and the generated typings for the route names still have the ___en extension, even after removing ./.nuxt and running my dev script again

@victorgarciaesgi
Copy link
Owner

Hmm that's weird, can you share me your pages forlder structure, and your i18n config?

@kerunix
Copy link

kerunix commented Feb 22, 2023

Sure, here's the output of tree fro my pages folder

pages
├── account
│   ├── auth
│   │   ├── email-verify
│   │   │   └── [id]
│   │   │       └── [hash].vue
│   │   ├── forgot-password.vue
│   │   ├── login.vue
│   │   ├── reset-password
│   │   │   ├── email.vue
│   │   │   ├── reset.vue
│   │   │   └── success.vue
│   │   ├── set-password.vue
│   │   ├── sign-up.vue
│   │   └── validate-email.vue
│   ├── auth.vue
│   ├── dashboard
│   │   ├── user-bookings.vue
│   │   └── user-profile.vue
│   ├── dashboard.vue
│   └── index.vue
└── index.vue

And here is everything relevant for the i18n options

export const i18n: NuxtI18nOptions = {
  locales: [
    {
      code: 'en',
      iso: 'en-US',
      file: 'en-US.json',
    },
    {
      code: 'fr',
      iso: 'fr-FR',
      file: 'fr-FR.json',
    },
  ],
  defaultLocale: 'fr',
  lazy: true,
  langDir: 'locales/',
  strategy: 'prefix_and_default',
  rootRedirect: 'fr/',
  vueI18n: {
    fallbackLocale: 'fr',
    legacy: false,
    fallbackWarn: false,
    missingWarn: false,
  },
}

And here are the typings generated by nuxt-typed-router in ./.nuxt/typed-router/__routes.ts (not the whole file, I just included what I thought to be relevent)

/**
 * Exhaustive list of all the available route names in the app
 * */
export type RoutesNamesList =
  | 'account-auth-email-verify-id-hash___en'
  | 'account-auth-forgot-password___en'
  | 'account-auth-login___en'
  | 'account-auth-reset-password-email___en'
  | 'account-auth-reset-password-reset___en'
  | 'account-auth-reset-password-success___en'
  | 'account-auth-set-password___en'
  | 'account-auth-sign-up___en'
  | 'account-auth-validate-email___en'
  | 'account-auth-email-verify-id-hash___fr___default'
  | 'account-auth-forgot-password___fr___default'
  | 'account-auth-login___fr___default'
  | 'account-auth-reset-password-email___fr___default'
  | 'account-auth-reset-password-reset___fr___default'
  | 'account-auth-reset-password-success___fr___default'
  | 'account-auth-set-password___fr___default'
  | 'account-auth-sign-up___fr___default'
  | 'account-auth-validate-email___fr___default'
  | 'account-dashboard-user-bookings___en'
  | 'account-dashboard-user-profile___en'
  | 'account-dashboard-user-bookings___fr___default'
  | 'account-dashboard-user-profile___fr___default'
  | 'account___en'
  | 'account___fr___default'
  | 'index___en'
  | 'index___fr___default'
  | 'index___fr';

@victorgarciaesgi
Copy link
Owner

Oh I see, it comes from prefix_and_default strategy that adds a additional ___default to the route name, how would you prefer it to be handled?

@victorgarciaesgi
Copy link
Owner

victorgarciaesgi commented Feb 22, 2023

For the route name, the only thing that I can rely on checking is keeping the xxx___default and removing the others

@kerunix
Copy link

kerunix commented Feb 22, 2023

Well since the localePath() helper of @nuxt/I18n is responsible for the matching of the localized route, I'd say that everything like ___xxx and ___xxx___default should be removed, leaving us only with the route names that would have been generated by Nuxt itself.

@victorgarciaesgi
Copy link
Owner

Problem is.. I already rely on Nuxt generated route names, and @nuxtjs/i18n overrides routes names with the xxx___default ones :/

Exemple output of nuxt pages
image

@kerunix
Copy link

kerunix commented Feb 22, 2023

I have not read your sources yet so maybe this is a wrong idea but my guess is that you exclude the i18n siblings from the generation, keeping only one route per page.

Maybe then before converting this route's name to a type you could split() it's name at ___ and use only the first returned index to generate the type litteral ?

@kerunix
Copy link

kerunix commented Feb 22, 2023

Although this might not be very robust since @nuxt/i18n has a configuration option for routesNameSeparator so there's no way to be sure that ___ would be the right thing to look for. I guess this could be achieved through a configuration option for the module, like i18nSeparator ?

EDIT: Sent a PR of how I believe this could be done, feel free to improve on that (or ask me to improve on it)

@victorgarciaesgi
Copy link
Owner

The separator should not be a problem as I can access the @nuxt/i18n config options!

@victorgarciaesgi
Copy link
Owner

Thanks for your PR! I guess it should be a good idea to keep the ___default route, and to pretify it

@kerunix
Copy link

kerunix commented Feb 22, 2023

I guess it should be a good idea to keep the ___default route, and to pretify it

I'm not sur I understand what you mean here.

@victorgarciaesgi
Copy link
Owner

I will show a simple exemple

In means transform this:

  | 'account___en'
  | 'account___fr'
  | 'account___fr___default'
  | 'index___en'
  | 'index___fr___default'
  | 'index___fr';

Into this

  | 'account'
  | 'index';

@victorgarciaesgi
Copy link
Owner

You can test it on 3.0.0-beta.8

commit: f02f7cb

@kerunix
Copy link

kerunix commented Feb 22, 2023

It's working ! 🥳

@victorgarciaesgi
Copy link
Owner

Also published another update, that let path autocomplete display and validates all available routes, but only shows and validate default routes for localePath.
You can try it with 3.0.0-beta.9

image
image

@Jassmin586
Copy link

This works fine for prefix_and_default, thanks ;) How about i18n prefix_except_default strategy?
In this option routesNames keys have name with language prefix.

2023-02-27_11-09

"nuxt-typed-router": "^3.0.1"
"@nuxtjs/i18n": "^8.0.0-beta.6"

@victorgarciaesgi
Copy link
Owner

@Jassmin586 Could you create an another issue for this? I think this one may be too clutered already 😂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants