Spreadsheet-UX op een echte relationele engine
Deze repository wordt als momentopname gepubliceerd: een clone bevat de volledige inhoud, maar geen commitgeschiedenis.
/**
* The languages Wellformed speaks, and the one setting that chooses between
* them.
*
* A locale here is a property of the *workspace*, like its currency: it
* decides the words in the chrome, the comma inside a number, the order
* inside a date — the same for everyone who opens it. It briefly lived on the
* account instead, on the theory that words belong to the reader, but a
* workspace is full of proper names — tables, columns, views — written in one
* language, and chrome in another language around them reads like two
* products taped together. One set of books, one language, one way of writing
* what is in them.
*
* Outside a workspace — the login page, the marketing page, mail to someone
* locked out — there is nothing to ask, and the browser's language decides.
*/
export const SUPPORTED_LOCALES = ['en', 'nl'] as const;
export type Locale = (typeof SUPPORTED_LOCALES)[number];
/** What a reader gets when neither they nor their browser expressed a wish. */
export const DEFAULT_LOCALE: Locale = 'en';
/**
* Each language named in itself, because the picker is read by exactly the
* person who may not understand the language the rest of the page is in.
*/
export const LOCALE_LABELS: Record<Locale, string> = {
en: 'English',
nl: 'Nederlands',
};
/**
* The BCP 47 tag `Intl` formats under for each UI language.
*
* Broader than the language alone: 'en' could format as en-GB or en-US and
* they disagree about dates. Picking one region per language keeps every
* installation rendering identically instead of drifting with the server's or
* the browser's own idea of English.
*/
export const FORMAT_LOCALES: Record<Locale, string> = {
en: 'en-US',
nl: 'nl-NL',
};
export function isLocale(value: unknown): value is Locale {
return typeof value === 'string' && (SUPPORTED_LOCALES as readonly string[]).includes(value);
}
/**
* Pick the best supported locale from an ordered preference list, e.g.
* `navigator.languages` or a parsed Accept-Language header.
*
* Only the primary subtag is compared: 'nl-BE' is somebody who reads Dutch,
* and telling them "sorry, only nl-NL here" by answering in English would be
* the wrong kind of precision.
*/
export function resolveLocale(preferences: readonly string[]): Locale {
for (const pref of preferences) {
const primary = pref.trim().toLowerCase().split('-')[0];
if (isLocale(primary)) return primary;
}
return DEFAULT_LOCALE;
}