Skip to content

Commit

Permalink
GN-4772: Fix supported language detection
Browse files Browse the repository at this point in the history
  • Loading branch information
dkozickis committed Apr 12, 2024
1 parent 43e33d6 commit 8b3fab9
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 22 deletions.
5 changes: 5 additions & 0 deletions .changeset/calm-llamas-protect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"frontend-gelinkt-notuleren": patch
---

GN-4772: Fix supported language detection
53 changes: 31 additions & 22 deletions app/utils/intl.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,43 @@
const matchUserLocaleToSupportedLocale = (userLocale, supportedLocales) => {
// Check if there is an exact match, e.g. nl-be === nl-be
const supportedLocale = supportedLocales.find(
(locale) => locale === userLocale,
);

if (supportedLocale) {
return supportedLocale;
}

// Check if there is a match based on language, e.g. nl === nl-be
const language = userLocale.split('-')[0];
return supportedLocales.find((locale) =>
locale.toLowerCase().startsWith(language.toLowerCase()),
);
};

/**
* Helper function to help pick supported locales for ember-intl.
* Returns exact matches first, then language matches, then the default.
*
* @param {string[]} userLocales - The user's locales, in order of preference,
* possibly from `navigator.languages`
* @param {string[]} supportedLocales - The locales the app supports, provided by `ember-intl`.
* @param {string} defaultLocale - The default fallback locale.
*
* @returns {string[]} - The supported locales, in order of preference.
**/
export function decentLocaleMatch(
userLocales,
supportedLocales,
defaultLocale,
) {
// Ember-intl lowercases locales so we can make comparisons easier by doing the same
const userLocs = userLocales.map((locale) => locale.toLowerCase());
const supportedLocs = supportedLocales.map((locale) => locale.toLowerCase());

// First find exact matches. Use a set to avoid duplicates while preserving insert order.
const matches = new Set(
userLocs.filter((locale) => supportedLocs.includes(locale)),
const supportedLocalesThatUserPrefers = userLocales.map((userLocale) =>
matchUserLocaleToSupportedLocale(userLocale, supportedLocales),
);

// Then look for locales that just match based on language,
// e.g. match en or en-US if looking for en-GB
const languageMap = {};
supportedLocs.forEach((locale) => {
const lang = locale.split('-')[0];
languageMap[lang] = [...(languageMap[lang] || []), locale];
});
userLocs.forEach((locale) => {
const looseMatches = languageMap[locale.split('-')[0]] ?? [];
looseMatches.forEach((match) => matches.add(match));
});
const deduplicatedSupportedLocales = new Set([
...supportedLocalesThatUserPrefers.map((locale) => locale.toLowerCase()),
defaultLocale.toLowerCase(),
]);

// Add the default so we always have something
matches.add(defaultLocale.toLowerCase());
return [...matches];
return [...deduplicatedSupportedLocales];
}
35 changes: 35 additions & 0 deletions tests/unit/utils/intl-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { module, test } from 'qunit';

import { decentLocaleMatch } from 'frontend-gelinkt-notuleren/utils/intl';

const supportedLocales = ['en-us', 'nl-BE'];
const defaultLocale = 'nl-BE';

module('Unit | Utils | intl', function () {
test.each(
'decentLocaleMatch',
[
{
userLocales: ['nl-NL', 'nl', 'en-US', 'en'],
expectedResult: ['nl-be', 'en-us'],
},
{
userLocales: ['nl-NL', 'nl'],
expectedResult: ['nl-be'],
},
{
userLocales: ['en-US', 'en', 'nl-NL', 'nl'],
expectedResult: ['en-us', 'nl-be'],
},
],
(assert, { userLocales, expectedResult }) => {
const result = decentLocaleMatch(
userLocales,
supportedLocales,
defaultLocale,
);

assert.deepEqual(result, expectedResult);
},
);
});

0 comments on commit 8b3fab9

Please sign in to comment.