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:
@@ -1,6 +1,5 @@
|
||||
import {lstatSync, readdirSync} from 'fs';
|
||||
import {lstatSync, readdirSync, readFileSync} from 'fs';
|
||||
import {createInstance, i18n} from 'i18next';
|
||||
import i18fsBackend from 'i18next-fs-backend';
|
||||
import {LanguageDetector} from 'i18next-http-middleware';
|
||||
import path from 'path';
|
||||
|
||||
@@ -10,42 +9,41 @@ export function setupLocale(appRoot: string): i18n {
|
||||
// By default locales are located in the appRoot folder, unless the environment variable
|
||||
// GRIST_LOCALES_DIR is set.
|
||||
const localeDir = process.env.GRIST_LOCALES_DIR || path.join(appRoot, 'static', 'locales');
|
||||
const preload: [string, string, string][] = [];
|
||||
const supportedNamespaces: Set<string> = new Set();
|
||||
const supportedLngs: Set<string> = new Set(readdirSync(localeDir).map((fileName) => {
|
||||
const supportedLngs: Set<string> = new Set();
|
||||
|
||||
for(const fileName of readdirSync(localeDir)) {
|
||||
const fullPath = path.join(localeDir, fileName);
|
||||
const isDirectory = lstatSync(fullPath).isDirectory();
|
||||
if (isDirectory) {
|
||||
return "";
|
||||
continue;
|
||||
}
|
||||
const baseName = path.basename(fileName, '.json');
|
||||
const lang = baseName.split('.')[0];
|
||||
const lang = baseName.split('.')[0]?.replace(/_/g, '-');
|
||||
const namespace = baseName.split('.')[1];
|
||||
if (!lang || !namespace) {
|
||||
throw new Error("Unrecognized resource file " + fileName);
|
||||
}
|
||||
supportedNamespaces.add(namespace);
|
||||
return lang;
|
||||
}).filter((lang) => lang));
|
||||
preload.push([lang, namespace, fullPath]);
|
||||
supportedLngs.add(lang);
|
||||
}
|
||||
|
||||
if (!supportedLngs.has('en') || !supportedNamespaces.has('server')) {
|
||||
throw new Error("Missing server English language file");
|
||||
}
|
||||
// Initialize localization filesystem plugin that will read the locale files from the localeDir.
|
||||
instance.use(i18fsBackend);
|
||||
// Initialize localization language detector plugin that will read the language from the request.
|
||||
instance.use(LanguageDetector);
|
||||
|
||||
let errorDuringLoad: Error | undefined;
|
||||
instance.init({
|
||||
// Load all files synchronously.
|
||||
initImmediate: false,
|
||||
preload: [...supportedLngs],
|
||||
supportedLngs: [...supportedLngs],
|
||||
defaultNS: 'server',
|
||||
ns: [...supportedNamespaces],
|
||||
fallbackLng: 'en',
|
||||
backend: {
|
||||
loadPath: `${localeDir}/{{lng}}.{{ns}}.json`
|
||||
},
|
||||
detection: {
|
||||
lookupCookie: 'grist_user_locale'
|
||||
}
|
||||
}, (err: any) => {
|
||||
if (err) {
|
||||
errorDuringLoad = err;
|
||||
@@ -56,14 +54,19 @@ export function setupLocale(appRoot: string): i18n {
|
||||
console.error("i18next failed unexpectedly", err);
|
||||
});
|
||||
if (errorDuringLoad) {
|
||||
console.error('i18next failed to load', errorDuringLoad);
|
||||
throw errorDuringLoad;
|
||||
}
|
||||
// Load all files synchronously.
|
||||
for(const [lng, ns, fullPath] of preload) {
|
||||
instance.addResourceBundle(lng, ns, JSON.parse(readFileSync(fullPath, 'utf8')));
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
export function readLoadedLngs(instance?: i18n): readonly string[] {
|
||||
if (!instance) { return []; }
|
||||
return instance?.options.preload || ['en'];
|
||||
return Object.keys(instance?.services.resourceStore.data);
|
||||
}
|
||||
|
||||
export function readLoadedNamespaces(instance?: i18n): readonly string[] {
|
||||
|
||||
Reference in New Issue
Block a user