handmade-revolt/src/mobx/stores/LocaleOptions.ts

107 lines
2.3 KiB
TypeScript

import { action, computed, makeAutoObservable } from "mobx";
import { Language, Languages } from "../../context/Locale";
import Persistent from "../interfaces/Persistent";
import Store from "../interfaces/Store";
import Syncable from "../interfaces/Syncable";
export interface Data {
lang: Language;
}
/**
* Detect the browser language or match given language.
* @param lang Language to find
* @returns Matched Language
*/
export function findLanguage(lang?: string): Language {
if (!lang) {
if (typeof navigator === "undefined") {
lang = Language.ENGLISH;
} else {
lang = navigator.language;
}
}
const code = lang.replace("-", "_");
const short = code.split("_")[0];
const values = [];
for (const key in Language) {
const value = Language[key as keyof typeof Language];
// Skip alternative/joke languages
if (Languages[value].cat === "alt") continue;
values.push(value);
if (value.startsWith(code)) {
return value as Language;
}
}
for (const value of values.reverse()) {
if (value.startsWith(short)) {
return value as Language;
}
}
return Language.ENGLISH;
}
/**
* Keeps track of user's language settings.
*/
export default class LocaleOptions
implements Store, Persistent<Data>, Syncable
{
private lang: Language;
/**
* Construct new LocaleOptions store.
*/
constructor() {
this.lang = findLanguage();
makeAutoObservable(this);
}
get id() {
return "locale";
}
toJSON() {
return {
lang: this.lang,
};
}
apply(_key: "locale", data: unknown, _revision: number): void {
this.hydrate(data as Data);
}
@computed toSyncable(): { [key: string]: object } {
return {
locale: this.toJSON(),
};
}
@action hydrate(data: Data) {
this.setLanguage(data.lang);
}
/**
* Get current language.
*/
@computed getLanguage() {
return this.lang;
}
/**
* Set current language.
*/
@action setLanguage(language: Language) {
if (typeof Languages[language] === "undefined") return;
this.lang = language;
}
}