mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) User language switcher
Summary: New language selector on the Account page for logged-in users. New icon for switching language for an anonymous user. For anonymous users, language is stored in a cookie grist_user_locale. Language is stored in user settings for authenticated users and takes precedence over what is stored in the cookie. Test Plan: New tests Reviewers: paulfitz Reviewed By: paulfitz Differential Revision: https://phab.getgrist.com/D3766
This commit is contained in:
@@ -6,18 +6,7 @@ import {G} from 'grainjs/dist/cjs/lib/browserGlobals';
|
||||
export async function setupLocale() {
|
||||
const now = Date.now();
|
||||
const supportedLngs = getGristConfig().supportedLngs ?? ['en'];
|
||||
let lng = window.navigator.language || 'en';
|
||||
// If user agent language is not in the list of supported languages, use the default one.
|
||||
lng = lng.replace(/-/g, '_');
|
||||
if (!supportedLngs.includes(lng)) {
|
||||
// Test if server supports general language.
|
||||
if (lng.includes("_") && supportedLngs.includes(lng.split("_")[0])) {
|
||||
lng = lng.split("_")[0]!;
|
||||
} else {
|
||||
lng = 'en';
|
||||
}
|
||||
}
|
||||
|
||||
const lng = detectCurrentLang();
|
||||
const ns = getGristConfig().namespaces ?? ['client'];
|
||||
// Initialize localization plugin
|
||||
try {
|
||||
@@ -25,8 +14,6 @@ export async function setupLocale() {
|
||||
i18next.init({
|
||||
// By default we use english language.
|
||||
fallbackLng: 'en',
|
||||
// Fallback from en-US, en-GB, etc to en.
|
||||
nonExplicitSupportedLngs: true,
|
||||
// We will load resources ourselves.
|
||||
initImmediate: false,
|
||||
// Read language from navigator object.
|
||||
@@ -38,8 +25,7 @@ export async function setupLocale() {
|
||||
// for now just import all what server offers.
|
||||
// We can fallback to client namespace for any addons.
|
||||
fallbackNS: 'client',
|
||||
ns,
|
||||
supportedLngs
|
||||
ns
|
||||
}).catch((err: any) => {
|
||||
// This should not happen, the promise should be resolved synchronously, without
|
||||
// any errors reported.
|
||||
@@ -51,14 +37,14 @@ export async function setupLocale() {
|
||||
const loadPath = `${document.baseURI}locales/{{lng}}.{{ns}}.json`;
|
||||
const pathsToLoad: Promise<any>[] = [];
|
||||
async function load(lang: string, n: string) {
|
||||
const resourceUrl = loadPath.replace('{{lng}}', lang).replace('{{ns}}', n);
|
||||
const resourceUrl = loadPath.replace('{{lng}}', lang.replace("-", "_")).replace('{{ns}}', n);
|
||||
const response = await fetch(resourceUrl);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load ${resourceUrl}`);
|
||||
}
|
||||
i18next.addResourceBundle(lang, n, await response.json());
|
||||
}
|
||||
for (const lang of languages) {
|
||||
for (const lang of languages.filter((l) => supportedLngs.includes(l))) {
|
||||
for (const n of ns) {
|
||||
pathsToLoad.push(load(lang, n));
|
||||
}
|
||||
@@ -70,6 +56,25 @@ export async function setupLocale() {
|
||||
}
|
||||
}
|
||||
|
||||
export function detectCurrentLang() {
|
||||
const { userLocale, supportedLngs } = getGristConfig();
|
||||
const detected = userLocale
|
||||
|| document.cookie.match(/grist_user_locale=([^;]+)/)?.[1]
|
||||
|| window.navigator.language
|
||||
|| 'en';
|
||||
const supportedList = supportedLngs ?? ['en'];
|
||||
// If we have this language in the list (or more general version) mark it as selected.
|
||||
// Compare languages in lower case, as navigator.language can return en-US, en-us (for older Safari).
|
||||
const selected = supportedList.find(supported => supported.toLowerCase() === detected.toLowerCase()) ??
|
||||
supportedList.find(supported => supported === detected.split(/[-_]/)[0]) ?? 'en';
|
||||
return selected;
|
||||
}
|
||||
|
||||
export function setAnonymousLocale(lng: string) {
|
||||
document.cookie = lng ? `grist_user_locale=${lng}; path=/; max-age=31536000`
|
||||
: 'grist_user_locale=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC';
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the translation of the given key using the given options.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user