From a8039e6b1dd676f0233bfddb09de089d1a508b60 Mon Sep 17 00:00:00 2001 From: 3y3 <3y3@ya.ru> Date: Thu, 7 Sep 2023 17:11:14 +0300 Subject: [PATCH] feat: Add `configure` util --- .eslintrc | 4 ---- .eslintrc.js | 15 +++++++++++++ .eslintrc.publish.js | 4 ++++ src/config/i18n.ts | 44 +++++++++++++++++++++++++++++++++++++ src/config/index.ts | 34 ++++++++++++++++++++++++++++ src/hooks/index.ts | 1 + src/hooks/useTranslation.ts | 8 +++++++ 7 files changed, 106 insertions(+), 4 deletions(-) delete mode 100644 .eslintrc create mode 100644 .eslintrc.js create mode 100644 .eslintrc.publish.js create mode 100644 src/config/i18n.ts create mode 100644 src/config/index.ts create mode 100644 src/hooks/useTranslation.ts diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index b4c98570..00000000 --- a/.eslintrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": ["@gravity-ui/eslint-config"], - "root": true -} diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..bc9579de --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,15 @@ +module.exports = { + extends: ['@gravity-ui/eslint-config'], + root: true, + rules: { + 'no-param-reassign': 'off', + }, + overrides: [ + { + files: ['!src/**/*', '!demo/**/*'], + env: { + node: true, + }, + }, + ], +}; diff --git a/.eslintrc.publish.js b/.eslintrc.publish.js new file mode 100644 index 00000000..e54537de --- /dev/null +++ b/.eslintrc.publish.js @@ -0,0 +1,4 @@ +module.exports = { + extends: ['@gravity-ui/eslint-config/prettier', './.eslintrc.js'], + root: true, +}; diff --git a/src/config/i18n.ts b/src/config/i18n.ts new file mode 100644 index 00000000..4f04a66d --- /dev/null +++ b/src/config/i18n.ts @@ -0,0 +1,44 @@ +import i18n, {TFunction} from 'i18next'; +import {initReactI18next} from 'react-i18next'; + +import en from '../i18n/en.json'; +import ru from '../i18n/ru.json'; +import {Lang} from '../models'; + +export type Loc = Record; + +export interface I18NConfig { + lang?: string; + loc?: Loc; +} + +let initializePromise: Promise | null = null; + +export const configureI18N = ({lang, loc}: I18NConfig) => { + if (initializePromise === null) { + lang = lang || Lang.En; + loc = loc || {ru, en}; + + initializePromise = i18n.use(initReactI18next).init({ + lng: lang, + fallbackLng: lang, + ns: Object.keys(loc[lang as Lang]), + resources: loc, + interpolation: { + escapeValue: false, + }, + }); + } else { + if (lang && lang !== i18n.language) { + i18n.changeLanguage(lang); + } + + if (loc) { + for (const [lng, namespaces] of Object.entries(loc)) { + for (const [ns, resources] of Object.entries(namespaces as Loc[Lang])) { + i18n.addResources(lng, ns, resources); + } + } + } + } +}; diff --git a/src/config/index.ts b/src/config/index.ts new file mode 100644 index 00000000..c3eb0a54 --- /dev/null +++ b/src/config/index.ts @@ -0,0 +1,34 @@ +import {Config, Lang} from '../models'; + +import {configureI18N} from './i18n'; + +type Subscriber = (config: Config) => void; + +const subs: Set = new Set(); + +let config: Config = { + lang: Lang.En, +}; + +export const configure = (newConfig: Partial = {}) => { + config = Object.assign({}, config, newConfig); + + configureI18N({ + lang: config.lang, + loc: config.loc, + }); + + subs.forEach((sub) => { + sub(config); + }); +}; + +export const subscribeConfigure = (sub: Subscriber) => { + subs.add(sub); + + return () => { + subs.delete(sub); + }; +}; + +export const getConfig = () => config; diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 2667adf3..10e96b6b 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -1,2 +1,3 @@ export * from './useForkRef'; export * from './usePopper'; +export * from './useTranslation'; diff --git a/src/hooks/useTranslation.ts b/src/hooks/useTranslation.ts new file mode 100644 index 00000000..ce69ede0 --- /dev/null +++ b/src/hooks/useTranslation.ts @@ -0,0 +1,8 @@ +import {useTranslation as useTranslationI18N} from 'react-i18next'; + +import {configure} from '../config'; + +export function useTranslation(...args: Parameters) { + configure(); + return useTranslationI18N(...args); +}