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

Support an array of locales to set the current locale #202

Open
cupcakearmy opened this issue Nov 19, 2022 · 9 comments · May be fixed by #204
Open

Support an array of locales to set the current locale #202

cupcakearmy opened this issue Nov 19, 2022 · 9 comments · May be fixed by #204

Comments

@cupcakearmy
Copy link
Contributor

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

This lib has the notion of a single locale store. From there possible variations are extrapolated.

export function getClosestAvailableLocale(

However in the real world both the Accept-Language headers and navigator.languages expose multiple languages, in order of user preference. This is a very useful feature as they can be used as a fallback if a specific is not available, before falling back to the global fallbackLocale

The issue is that right now this logic is not exposed and needs to be handled by the developer by iterating the available languages, creating subsets (en, en-US, etc.) and then match them agains the $locales available in the lib.

Describe the solution you'd like

Since the language matching feature is already in the codabase and does basically that one could:

  1. Either expose those functions so they don't need to be duplicated by the dev.
  2. Allow the $locale store to also, beside a string, give a list of strings.

Personally I'd say options 2 is the way to go

Describe alternatives you've considered

Write the logic in every project, for every dev. def. duable but it's a pity as most of the logic, as stated above, is alrady in the lib.

How important is this feature to you?

Not dealbreaking but it would def. be a welcome addition.

Additional context

@kaisermann
Copy link
Owner

Hey @cupcakearmy 👋

The issue is that right now this logic is not exposed and needs to be handled by the developer by iterating the available languages, creating subsets (en, en-US, etc.) and then match them agains the $locales available in the lib.

Not sure I'm following 100% 😅 Can you exemplify why you need this logic in the app?

@cupcakearmy
Copy link
Contributor Author

Sure!

So immagine a site X has localised content for ['en', 'de', 'es']. A user Y has it's browser/os setup with italian as first and spanish as second languge. this resulst in accept-language and window.navigator.languages to have a content similar to it,es.

Currently, as the lib only supports one language, the webpage would try to load locales for it, not finding them and falling back to en. However in theory they would have had es in common.

So we need to write additional code to handle this behavior.

  1. Lookup what languages are available (en, de, es)
  2. See what languages are preferred by the user (it, es) and generate subversions of it (it-IT -> it, etc.)
  3. Match the first best, or default to the fallback one <- this behaviour is already in the library if i'm not mistaken

Hope this clears up the confusion :)

@kaisermann
Copy link
Owner

Got it, thanks! Changing the $locale store to an array would be a breaking change and I would say that users would usually expect it to return the current locale being used. That said, nothing prevents us from making it accept an array as input.

$locale = navigator.languages or locale.set(['en', 'de', 'es']) => would resolve to es

It may be a bit weird to assign it to an array and have a string as the actual value though 🤔

@cupcakearmy
Copy link
Contributor Author

Yes, would not enforce it as array, only as an accepted value, as it's not the most common use case. Maybe one could add a currentLocale store? Up to you :)

@kaisermann
Copy link
Owner

kaisermann commented Nov 19, 2022

Maybe one could add a currentLocale store? Up to you :)

Thought about it too. Would still be a breaking change, though 😅

Yes, would not enforce it as array

I meant accepting an array as an input, but the output would always be a single string. However, while I was typing this I thought that maybe typing a store in such a way is not possible 🙈

Anyway, my point is that it seems the "array" is only useful as an input to define the initial locale, correct? I wouldn't want to complicate the usage of the $locale in all the other places it may be used just because of it. I will sit on this for a bit, but suggestions and feedbacks are always welcome 🙏


We could change how we recommend changing the locale. Right now, one should modify the $locale store directly. We could keep this but introduce a setLocale or changeLocale function that would be the one that accepted both string and an array of strings.

@cupcakearmy
Copy link
Contributor Author

I agree on every point :)

It's def. an initialization thing. So a helper function would be also enough, to choose the most approriate locale, and leave the whole $locale untouched, which is def. a good thing :)

I think it might be possible with proxies, but yes, introduces unecessary "magic"

@kaisermann
Copy link
Owner

kaisermann commented Nov 19, 2022

I'm still exploring modifying the $locale.set approach. One limitation though is that to know what locale to use from an array, the consumer must have already registered/added messages to the dictionary:

Using your example, given that there are messages registered for these three languages, we can decide which one to "set" as the $locale value based on them.

  init({
    fallbackLocale: 'en',
  });

  register('en', () => Promise.resolve({ foo: 'Foo' }));
  register('de', () => Promise.resolve({ foo: 'Foo' }));
  register('es', () => Promise.resolve({ foo: 'Foo' }));

  expect(get($locale)).toBe('en');

  await $locale.set(['it', 'es']);

  expect(get($locale)).toBe('es');

What should happen with the value of $locale if the locales passed in the array are not available? Should it fallback to the fallbackLocale? The current behaviour would be to leave the $locale store value as undefined.

I'm inclined to leave it as undefined and the rest of the work to the already existing logic for fallbacking to the fallbackLocale when formatting a message

@kaisermann kaisermann linked a pull request Nov 19, 2022 that will close this issue
@kaisermann
Copy link
Owner

kaisermann commented Nov 19, 2022

I've released an alpha version 3.5.0-alpha.0 and this is the PR. I can't test this within the scope of Svelte right now though

@kaisermann kaisermann changed the title Add support for multiple languages. Support an array of locales to set the current locale Nov 19, 2022
@bjbk
Copy link

bjbk commented May 29, 2024

I may have missed this in the tread, but what about the fallbackLocale as an Object or Array instead? vue-i18n has something like this:

fallbackLocale: {
    'en-ie': ['en-gb'],
    pap: ['nl'],
    es: ['en-gb'],
    ase: ['en-us'],
    fcs: ['fr-ca'],
    lsb: ['fr'],
    'pt-br': ['pt', 'es'],
    no: ['en-us'],
    default: ['en-us', 'en']
  }

I have to support many languages and having a graceful fallback can be helpful. Of course the example above is complex but gives the idea of a cascade type fallback hierarchy.
For each locale, an array of locales can be set as a fallback with (in this case) English as a last resort.

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

Successfully merging a pull request may close this issue.

3 participants