only offer languages that have been marked as substantially complete (#466)

This checks for languages that have a special key translated.
Any that don't have the key translated, are not offered to the
user (unless GRIST_OFFER_ALL_LANGUAGES is set).

Co-authored-by: jarek <jaroslaw.sadzinski@gmail.com>
This commit is contained in:
Paul Fitzpatrick 2023-03-28 10:59:17 -04:00 committed by GitHub
parent 503e56db40
commit a941a72904
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 25 additions and 5 deletions

View File

@ -261,6 +261,7 @@ GRIST_LIST_PUBLIC_SITES | if set to true, sites shared with the public will be l
GRIST_MANAGED_WORKERS | if set, Grist can assume that if a url targeted at a doc worker returns a 404, that worker is gone
GRIST_MAX_UPLOAD_ATTACHMENT_MB | max allowed size for attachments (0 or empty for unlimited).
GRIST_MAX_UPLOAD_IMPORT_MB | max allowed size for imports (except .grist files) (0 or empty for unlimited).
GRIST_OFFER_ALL_LANGUAGES | if set, all translated langauages are offered to the user (by default, only languages with a special 'good enough' key set are offered to user).
GRIST_ORG_IN_PATH | if true, encode org in path rather than domain
GRIST_PAGE_TITLE_SUFFIX | a string to append to the end of the `<title>` in HTML documents. Defaults to `" - Grist"`. Set to `_blank` for no suffix at all.
GRIST_PROXY_AUTH_HEADER | header which will be set by a (reverse) proxy webserver with an authorized users' email. This can be used as an alternative to a SAML service. See also GRIST_FORWARD_AUTH_HEADER.

View File

@ -1,3 +1,5 @@
import {appSettings} from 'app/server/lib/AppSettings';
import log from 'app/server/lib/log';
import {lstatSync, readdirSync, readFileSync} from 'fs';
import {createInstance, i18n} from 'i18next';
import {LanguageDetector} from 'i18next-http-middleware';
@ -26,7 +28,7 @@ export function setupLocale(appRoot: string): i18n {
throw new Error("Unrecognized resource file " + fileName);
}
supportedNamespaces.add(namespace);
preload.push([lang, namespace, fullPath]);
preload.push([namespace, lang, fullPath]);
supportedLngs.add(lang);
}
@ -51,15 +53,32 @@ export function setupLocale(appRoot: string): i18n {
}).catch((err: any) => {
// This should not happen, the promise should be resolved synchronously, without
// any errors reported.
console.error("i18next failed unexpectedly", err);
log.error("i18next failed unexpectedly", err);
});
if (errorDuringLoad) {
console.error('i18next failed to load', errorDuringLoad);
log.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')));
// First sort by ns, which will put "client" first. That lets us check for a
// client key which, if absent, means the language should be ignored.
preload.sort((a, b) => a[0].localeCompare(b[0]));
const offerAll = appSettings.section('locale').flag('offerAllLanguages').readBool({
envVar: 'GRIST_OFFER_ALL_LANGUAGES',
});
const shouldIgnoreLng = new Set<string>();
for(const [ns, lng, fullPath] of preload) {
const data = JSON.parse(readFileSync(fullPath, 'utf8'));
// If the "Translators: please ..." key in "App" has not been translated,
// ignore this language for this and later namespaces.
if (!offerAll && ns === 'client' &&
!Object.keys(data.App || {}).some(key => key.includes('Translators: please'))) {
shouldIgnoreLng.add(lng);
log.debug(`skipping incomplete language ${lng} (set GRIST_OFFER_ALL_LANGUAGES if you want it)`);
}
if (!shouldIgnoreLng.has(lng)) {
instance.addResourceBundle(lng, ns, data);
}
}
return instance;
}