From 70f285fa209fb8e846a0bf2d543479d5fa38e6af Mon Sep 17 00:00:00 2001 From: SleeplessOne1917 Date: Mon, 3 Apr 2023 09:28:56 -0400 Subject: [PATCH] I18 quality of life change (#973) * I18 quality of life change * Cleanup --- generate_translations.js | 66 +++++++++++++++++++++----- src/shared/components/app/no-match.tsx | 4 +- src/shared/components/home/signup.tsx | 4 +- 3 files changed, 57 insertions(+), 17 deletions(-) diff --git a/generate_translations.js b/generate_translations.js index 594f574c..ac3e9875 100644 --- a/generate_translations.js +++ b/generate_translations.js @@ -30,30 +30,70 @@ fs.readdir(translationDir, (_err, files) => { const baseLanguage = "en"; 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"; declare module "i18next" { - export type I18nKeys = -${keys.map(key => ` | "${key}"`).join("\n")}; - + export type NoOptionI18nKeys = +${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 =${Array.from( + optionMap.entries() + ).reduce( + (acc, [key, options]) => + `${acc} TKey extends \"${key}\" ? ${ + options.reduce((acc, cur) => acc + `${cur}: string | number; `, "{ ") + + "}" + } :\n${indent}`, + "" + )} (Record | string); + export interface TFunctionTyped { - // basic usage + // Translation requires options < + TKey extends OptionI18nKeys | OptionI18nKeys[], TResult extends TFunctionResult = string, - TInterpolationMap extends Record = StringMap - >( - key: I18nKeys | I18nKeys[], - options?: TOptions | string + TInterpolationMap extends TTypedOptions = StringMap + > ( + key: TKey, + options: TOptions | string ): TResult; - // overloaded usage + + // Translation does not require options < TResult extends TFunctionResult = string, TInterpolationMap extends Record = StringMap - >( - key: I18nKeys | I18nKeys[], - defaultValue?: string, + > ( + key: NoOptionI18nKeys | NoOptionI18nKeys[], options?: TOptions | string ): TResult; } diff --git a/src/shared/components/app/no-match.tsx b/src/shared/components/app/no-match.tsx index bf0eb6a8..6781e351 100644 --- a/src/shared/components/app/no-match.tsx +++ b/src/shared/components/app/no-match.tsx @@ -1,11 +1,11 @@ -import { I18nKeys } from "i18next"; +import { NoOptionI18nKeys } from "i18next"; import { Component } from "inferno"; import { i18n } from "../../i18next"; export class NoMatch extends Component { private errCode = new URLSearchParams(this.props.location.search).get( "err" - ) as I18nKeys; + ) as NoOptionI18nKeys; constructor(props: any, context: any) { super(props, context); diff --git a/src/shared/components/home/signup.tsx b/src/shared/components/home/signup.tsx index 5deb8026..aecba9f9 100644 --- a/src/shared/components/home/signup.tsx +++ b/src/shared/components/home/signup.tsx @@ -1,5 +1,5 @@ import { Options, passwordStrength } from "check-password-strength"; -import { I18nKeys } from "i18next"; +import { NoOptionI18nKeys } from "i18next"; import { Component, linkEvent } from "inferno"; import { T } from "inferno-i18next-dess"; import { @@ -231,7 +231,7 @@ export class Signup extends Component { /> {this.state.form.password && (
- {i18n.t(this.passwordStrength as I18nKeys)} + {i18n.t(this.passwordStrength as NoOptionI18nKeys)}
)}