I18 quality of life change (#973)

* I18 quality of life change

* Cleanup
This commit is contained in:
SleeplessOne1917 2023-04-03 09:28:56 -04:00 committed by GitHub
parent 16cb506147
commit e947549cdc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 17 deletions

View file

@ -30,30 +30,70 @@ fs.readdir(translationDir, (_err, files) => {
const baseLanguage = "en"; const baseLanguage = "en";
fs.readFile(`${translationDir}${baseLanguage}.json`, "utf8", (_, fileStr) => { fs.readFile(`${translationDir}${baseLanguage}.json`, "utf8", (_, fileStr) => {
const keys = Object.keys(JSON.parse(fileStr)); const noOptionKeys = [];
const optionKeys = [];
const optionRegex = /\{\{(.+?)\}\}/g;
const optionMap = new Map();
for (const [key, val] of Object.entries(JSON.parse(fileStr))) {
const options = [];
for (
let match = optionRegex.exec(val);
match;
match = optionRegex.exec(val)
) {
options.push(match[1]);
}
if (options.length > 0) {
optionMap.set(key, options);
optionKeys.push(key);
} else {
noOptionKeys.push(key);
}
}
const indent = " ";
const data = `import { i18n } from "i18next"; const data = `import { i18n } from "i18next";
declare module "i18next" { declare module "i18next" {
export type I18nKeys = export type NoOptionI18nKeys =
${keys.map(key => ` | "${key}"`).join("\n")}; ${noOptionKeys.map(key => `${indent}| "${key}"`).join("\n")};
export type OptionI18nKeys =
${optionKeys.map(key => `${indent}| "${key}"`).join("\n")};
export type I18nKeys = NoOptionI18nKeys | OptionI18nKeys;
export type TTypedOptions<TKey extends OptionI18nKeys> =${Array.from(
optionMap.entries()
).reduce(
(acc, [key, options]) =>
`${acc} TKey extends \"${key}\" ? ${
options.reduce((acc, cur) => acc + `${cur}: string | number; `, "{ ") +
"}"
} :\n${indent}`,
""
)} (Record<string, unknown> | string);
export interface TFunctionTyped { export interface TFunctionTyped {
// basic usage // Translation requires options
< <
TKey extends OptionI18nKeys | OptionI18nKeys[],
TResult extends TFunctionResult = string, TResult extends TFunctionResult = string,
TInterpolationMap extends Record<string, unknown> = StringMap TInterpolationMap extends TTypedOptions<TKey> = StringMap
>( > (
key: I18nKeys | I18nKeys[], key: TKey,
options?: TOptions<TInterpolationMap> | string options: TOptions<TInterpolationMap> | string
): TResult; ): TResult;
// overloaded usage
// Translation does not require options
< <
TResult extends TFunctionResult = string, TResult extends TFunctionResult = string,
TInterpolationMap extends Record<string, unknown> = StringMap TInterpolationMap extends Record<string, unknown> = StringMap
>( > (
key: I18nKeys | I18nKeys[], key: NoOptionI18nKeys | NoOptionI18nKeys[],
defaultValue?: string,
options?: TOptions<TInterpolationMap> | string options?: TOptions<TInterpolationMap> | string
): TResult; ): TResult;
} }

View file

@ -1,11 +1,11 @@
import { I18nKeys } from "i18next"; import { NoOptionI18nKeys } from "i18next";
import { Component } from "inferno"; import { Component } from "inferno";
import { i18n } from "../../i18next"; import { i18n } from "../../i18next";
export class NoMatch extends Component<any, any> { export class NoMatch extends Component<any, any> {
private errCode = new URLSearchParams(this.props.location.search).get( private errCode = new URLSearchParams(this.props.location.search).get(
"err" "err"
) as I18nKeys; ) as NoOptionI18nKeys;
constructor(props: any, context: any) { constructor(props: any, context: any) {
super(props, context); super(props, context);

View file

@ -1,5 +1,5 @@
import { Options, passwordStrength } from "check-password-strength"; import { Options, passwordStrength } from "check-password-strength";
import { I18nKeys } from "i18next"; import { NoOptionI18nKeys } from "i18next";
import { Component, linkEvent } from "inferno"; import { Component, linkEvent } from "inferno";
import { T } from "inferno-i18next-dess"; import { T } from "inferno-i18next-dess";
import { import {
@ -231,7 +231,7 @@ export class Signup extends Component<any, State> {
/> />
{this.state.form.password && ( {this.state.form.password && (
<div className={this.passwordColorClass}> <div className={this.passwordColorClass}>
{i18n.t(this.passwordStrength as I18nKeys)} {i18n.t(this.passwordStrength as NoOptionI18nKeys)}
</div> </div>
)} )}
</div> </div>