nuxt-modules / i18n

I18n module for Nuxt
https://i18n.nuxtjs.org
MIT License
1.73k stars 479 forks source link

Update "lazy" loading API #845

Closed varna closed 1 month ago

varna commented 4 years ago

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

I'm using a translation platform Phrase (something like POEditor). They provide "lots of" methods to receive translation files. But none of these methods seems to fit well with vue-i18n or i18n-module. Currently my favorite is vue-cli-plugin-i18n. You just yarn download-translations into a single folder before generating a project.

tl;dr:

  1. I don't have a list of locales (because I receive it from API).
  2. I don't have the files (because I receive them from API) (and it would be nice to cache them, because translators keep translating them).

Describe the solution you'd like

options.lazy (or some other new method like translations) should accept a string or async function:

const options = {

  // /locales contain `locale.(json|js)` translation files
  translations: `/locales`,

  // API (request handled by module)
  translations: locale => `https://translations.server/api/client_id/project_id/${locale}`,

  // custom request handling (some people might need custom headers)
  translations: async (locale) => axios(`https://translations.server/api/client_id/project_id/${locale}`).data
}

options.locales should be an optional list of locale Strings or async function:

const options = {

  locales: ['en', 'fr', 'es'],

  // API
  locales: async () => axios(`https://translations.server/api/client_id/project_id/locales-list`).data,

  // maybe we can infer locales from `translations` folder? Just like vue-cli plugin?
  locales: undefined
}

We might also need some mechanism to cache/invalidate locale list.

Describe alternatives you've considered

rchl commented 4 years ago

I think that downloading locales with a script is the most reliable approach. You know exactly what you are getting at deployment time, the translations are tracked by git so that you can review state at any point in history and if something fails you are not gonna end up with missing locales.

Why is that not a viable solution for you?

I suppose that supported locale list doesn't change often so it shouldn't be a problem to maintain that list manually. Also, if SEO is important to you then there are properties that have to be defined manually anyway as it wouldn't be possible to infer those automatically.

varna commented 4 years ago

I think that downloading locales with a script is the most reliable approach.

Yes, it is.

You know exactly what you are getting at deployment time, the translations are tracked by git so that you can review state at any point in history and if something fails you are not gonna end up with missing locales.

  1. You can add script to CI/CD. Then it wouldn't be tracked by Git.
  2. I don't like translations being tracked in Git. It's not like I hate it, but it adds additional "step" to development workflow. Which you need to document. Which has to be known by any developer that joins. And which I have to not forget myself after few months.

Why is that not a viable solution for you?

Separation of concerns. I think that app should be capable of working without pulling data into its own repository. I think that I don't like people coming to me and talking with me and giving me tasks like "We added new blablabla, can you publish it again?" I hope to get a vacation, without receiving a call. You might tell me to create a hook, but my provider might tell me to wait 6-24 months. Or simple ignore me. He might reconsider it after I start DDoSing him with "Do you have new content?" requests.

Thank you, @rchl, for you suggestion, but I want to try a new path, which I hope works a bit better with backend driven apps.

rchl commented 4 years ago

I think I don't agree with that approach.

I want (and that's how I think it should be) the app to be an immutable artifact. If I'm deploying the same app version at different times, I expect the same results every time and content (translations) not to change.

When translations change or new ones are added, that typically requires changes in the page content also (new translations are typically for new pages).

(An exception, I guess, is if your pages come from a CMS then it makes sense to have translations come from CMS-like service also.)

That said, there are feature requests for both having one single JS file for handling "lazy" loading and for accepting a function for the locales option so that those could be decided dynamically.

varna commented 4 years ago

Yes, there are some issues like:

Dynamic list of locales: https://github.com/nuxt-community/i18n-module/issues/256 Which is abandoned because of async nuxt.config.js solution. Which does solve the problem only during build time and not runtime.

Not lazy langDir: https://github.com/nuxt-community/i18n-module/issues/412 Is also stale. And I think that my offered approach is "better", because current api (lazy, langDir, locales) seems very... Rushed out. It is very verbose and unnecessarily complicated. I'd vote for a new major release with simplified API.

langDir does not support absolute path: https://github.com/nuxt-community/i18n-module/issues/792 And this one is treated as only bug report for absolute paths.

Custom loadLanguageAsync function: https://github.com/nuxt-community/i18n-module/issues/581 OK. I confess. I did miss this one one somehow.

Add support of non-git based messages source: https://github.com/nuxt-community/i18n-module/issues/833 And here this guy is trying to work with current API to deliver dynamic data.

To sum it up. My issue is a feature request to refactor current API for lazy, langDir, locales into a simpler and more manageable solution. This could be done when upgrading code for next major version with vue3, nuxt3 and https://github.com/intlify/vue-i18n-next

varna commented 4 years ago

I totally agree that an app should be immutable! But I don't agree that data/translations are always part of the app. I do agree for static pages, md based content etc. But not for headless runtime. I should probably try forking this repo because our opinions disagree.

rchl commented 4 years ago

Which is abandoned because

Nothing is abandoned as long as the issue is open. It just means I didn't have time to get to it yet. :)

Which does solve the problem only during build time and not runtime.

I don't see how to support runtime-locales as those need to be defined before the build is started so that appropriate extra routes are generated. That could likely only work for no_prefix strategy.

current api (lazy, langDir, locales) seems very... Rushed out. It is very verbose and unnecessarily complicated. I'd vote for a new major release with simplified API.

Can you help to define that new API? Having in mind that locales object can specify some SEO-related properties also and even any arbitrary properties in fact.

I should probably try forking this repo because our opinions disagree.

Our opinions might disagree but I didn't say that those aforementioned feature requests or issues are invalid. They just need to be attended to eventually. :)

varna commented 4 years ago

I don't see how to support runtime-locales as those need to be defined before the build is started so that appropriate extra routes are generated. That could likely only work for no_prefix strategy.

Thank you for reminding me! I totally forgot about "route generation". I wanted to ask: Why are you generating routes for locales instead of generating dynamic route "_locale"?

Can you help to define that new API? Having in mind that locales object can specify some SEO-related properties also and even any arbitrary properties in fact.

All properties of locale object are optional parameters (at least in my opinion). Example of a different approach for options:

Our opinions might disagree but I didn't say that those aforementioned feature requests or issues are invalid. They just need to be attended to eventually. :)

Thanks for caring!

rchl commented 4 years ago

Thank you for reminding me! I totally forgot about "route generation". I wanted to ask: Why are you generating routes for locales instead of generating dynamic route "_locale"?

I'm not sure. It was done like that when I've inherited this module. I suppose doing a dynamic locale would pose some challenges. At least locale validation would have to be done on the code level rather than relying on VueRouter validating it now. But it would have the benefit of generating fewer routes which would be good for performance.

varna commented 4 years ago

I'm not sure. It was done like that when I've inherited this module.

That's a fair answer.

I suppose doing a dynamic locale would pose some challenges.

Definitely. i.e. no-prefix route.

At least locale validation would have to be done on the code level rather than relying on VueRouter validating it now.

I'm not sure how it is done now. But I used to import same middleware to all locale route children before using i18n-module. It also brings me to another tricky question. Which is translated routes. i.e.

/_locale/$t('product')/$t(_slug)
/en/product/monitor
/lt/produktas/monitorius

Once I tried doing this with middlewares, trying to reverse translate URLs, then validating them and mapping to correct content. But it was... very clunky, big and ugly... and slow. I started thinking of simply using IDs in routes and just masking them with translated results. But I haven't even started the research of feasibility and SEO impact.

coremyslo commented 4 years ago

Sorry to step in.

I want (and that's how I think it should be) the app to be an immutable artifact. If I'm deploying the same app version at different times, I expect the same results every time and content (translations) not to change.

In my project, we expect translations can be managed in real-time on staging by the content team via 3rd party translation tool. In this case, translations are "data", and not the part of code.

I don't think "nuxt-18n" should provide a build-in solution for fetching content (like for lazyload) because the realization could be very different. But the place where custom code can be placed and some documented approach for doing it would be great.

varna commented 4 years ago

I agree with @coremyslo,

Extra code = larger bundle = slower project. We could type down the currently known uses cases, create some tests and update the docs.

rchl commented 4 years ago

i.e. no-prefix route.

We could generate just one extra route with the dynamic locale prefix and leave the existing, unprefixed untouched. So there would be just one extra route per route for all locales, rather than one extra route for each locale.

It also brings me to another tricky question. Which is translated routes.

Handling those dynamically sounds too crazy to me so I guess those could only be added at build time.

varna commented 4 years ago

We could generate just one extra route with the dynamic locale prefix and leave the existing, unprefixed untouched. So there would be just one extra route per route for all locales, rather than one extra route for each locale.

Agree.

Handling those dynamically sounds too crazy to me so I guess those could only be added at build time.

Actually, this sounds more like nuxt problem, not the module problem. Something like permalink option for pages items. i18n only needs to be accessible.

stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

BobbieGoede commented 1 month ago

Closing this as v7 is not being actively worked on (critical hotfixes only), if this still applies to v8 and later please open a new issue!