mirror of
https://github.com/langgenius/dify.git
synced 2026-02-09 15:10:13 -05:00
chore: fix type for useTranslation in #i18n (#32134)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -38,7 +38,7 @@ const DeprecationNotice: FC<DeprecationNoticeProps> = ({
|
||||
iconWrapperClassName,
|
||||
textClassName,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const { t } = useTranslation('plugin')
|
||||
|
||||
const deprecatedReasonKey = useMemo(() => {
|
||||
if (!deprecatedReason)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
import type { Resource } from 'i18next'
|
||||
import type { Locale } from '.'
|
||||
import type { NamespaceCamelCase, NamespaceKebabCase } from './resources'
|
||||
import type { Namespace, NamespaceInFileName } from './resources'
|
||||
import { kebabCase } from 'es-toolkit/string'
|
||||
import { createInstance } from 'i18next'
|
||||
import resourcesToBackend from 'i18next-resources-to-backend'
|
||||
@@ -14,7 +14,7 @@ export function createI18nextInstance(lng: Locale, resources: Resource) {
|
||||
.use(initReactI18next)
|
||||
.use(resourcesToBackend((
|
||||
language: Locale,
|
||||
namespace: NamespaceKebabCase | NamespaceCamelCase,
|
||||
namespace: NamespaceInFileName | Namespace,
|
||||
) => {
|
||||
const namespaceKebab = kebabCase(namespace)
|
||||
return import(`../i18n/${language}/${namespaceKebab}.json`)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
'use client'
|
||||
|
||||
import type { NamespaceCamelCase } from './resources'
|
||||
import type { Namespace } from './resources'
|
||||
import { useTranslation as useTranslationOriginal } from 'react-i18next'
|
||||
|
||||
export function useTranslation(ns?: NamespaceCamelCase) {
|
||||
export function useTranslation<T extends Namespace | undefined = undefined>(ns?: T) {
|
||||
return useTranslationOriginal(ns)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import type { NamespaceCamelCase } from './resources'
|
||||
import type { Namespace } from './resources'
|
||||
import { use } from 'react'
|
||||
import { getLocaleOnServer, getTranslation } from './server'
|
||||
|
||||
async function getI18nConfig(ns?: NamespaceCamelCase) {
|
||||
async function getI18nConfig<T extends Namespace | undefined = undefined>(ns?: T) {
|
||||
const lang = await getLocaleOnServer()
|
||||
return getTranslation(lang, ns)
|
||||
}
|
||||
|
||||
export function useTranslation(ns?: NamespaceCamelCase) {
|
||||
export function useTranslation<T extends Namespace | undefined = undefined>(ns?: T) {
|
||||
return use(getI18nConfig(ns))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { kebabCase } from 'es-toolkit/string'
|
||||
import { kebabCase } from 'string-ts'
|
||||
import { ObjectKeys } from '@/utils/object'
|
||||
import appAnnotation from '../i18n/en-US/app-annotation.json'
|
||||
import appApi from '../i18n/en-US/app-api.json'
|
||||
import appDebug from '../i18n/en-US/app-debug.json'
|
||||
@@ -64,19 +65,10 @@ const resources = {
|
||||
workflow,
|
||||
}
|
||||
|
||||
export type KebabCase<S extends string> = S extends `${infer T}${infer U}`
|
||||
? T extends Lowercase<T>
|
||||
? `${T}${KebabCase<U>}`
|
||||
: `-${Lowercase<T>}${KebabCase<U>}`
|
||||
: S
|
||||
|
||||
export type CamelCase<S extends string> = S extends `${infer T}-${infer U}`
|
||||
? `${T}${Capitalize<CamelCase<U>>}`
|
||||
: S
|
||||
|
||||
export type Resources = typeof resources
|
||||
export type NamespaceCamelCase = keyof Resources
|
||||
export type NamespaceKebabCase = KebabCase<NamespaceCamelCase>
|
||||
|
||||
export const namespacesCamelCase = Object.keys(resources) as NamespaceCamelCase[]
|
||||
export const namespacesKebabCase = namespacesCamelCase.map(ns => kebabCase(ns)) as NamespaceKebabCase[]
|
||||
export const namespaces = ObjectKeys(resources)
|
||||
export type Namespace = typeof namespaces[number]
|
||||
|
||||
export const namespacesInFileName = namespaces.map(ns => kebabCase(ns))
|
||||
export type NamespaceInFileName = typeof namespacesInFileName[number]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { i18n as I18nInstance, Resource, ResourceLanguage } from 'i18next'
|
||||
import type { Locale } from '.'
|
||||
import type { NamespaceCamelCase, NamespaceKebabCase } from './resources'
|
||||
import type { Namespace, NamespaceInFileName } from './resources'
|
||||
import { match } from '@formatjs/intl-localematcher'
|
||||
import { kebabCase } from 'es-toolkit/compat'
|
||||
import { camelCase } from 'es-toolkit/string'
|
||||
@@ -12,7 +12,7 @@ import { cache } from 'react'
|
||||
import { initReactI18next } from 'react-i18next/initReactI18next'
|
||||
import { serverOnlyContext } from '@/utils/server-only-context'
|
||||
import { i18n } from '.'
|
||||
import { namespacesKebabCase } from './resources'
|
||||
import { namespacesInFileName } from './resources'
|
||||
import { getInitOptions } from './settings'
|
||||
|
||||
const [getLocaleCache, setLocaleCache] = serverOnlyContext<Locale | null>(null)
|
||||
@@ -26,8 +26,8 @@ const getOrCreateI18next = async (lng: Locale) => {
|
||||
instance = createInstance()
|
||||
await instance
|
||||
.use(initReactI18next)
|
||||
.use(resourcesToBackend((language: Locale, namespace: NamespaceCamelCase | NamespaceKebabCase) => {
|
||||
const fileNamespace = kebabCase(namespace) as NamespaceKebabCase
|
||||
.use(resourcesToBackend((language: Locale, namespace: Namespace | NamespaceInFileName) => {
|
||||
const fileNamespace = kebabCase(namespace)
|
||||
return import(`../i18n/${language}/${fileNamespace}.json`)
|
||||
}))
|
||||
.init({
|
||||
@@ -38,7 +38,7 @@ const getOrCreateI18next = async (lng: Locale) => {
|
||||
return instance
|
||||
}
|
||||
|
||||
export async function getTranslation(lng: Locale, ns?: NamespaceCamelCase) {
|
||||
export async function getTranslation<T extends Namespace>(lng: Locale, ns?: T) {
|
||||
const i18nextInstance = await getOrCreateI18next(lng)
|
||||
|
||||
if (ns && !i18nextInstance.hasLoadedNamespace(ns))
|
||||
@@ -84,7 +84,7 @@ export const getResources = cache(async (lng: Locale): Promise<Resource> => {
|
||||
const messages = {} as ResourceLanguage
|
||||
|
||||
await Promise.all(
|
||||
(namespacesKebabCase).map(async (ns) => {
|
||||
(namespacesInFileName).map(async (ns) => {
|
||||
const mod = await import(`../i18n/${lng}/${ns}.json`)
|
||||
messages[camelCase(ns)] = mod.default
|
||||
}),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { InitOptions } from 'i18next'
|
||||
import { namespacesCamelCase } from './resources'
|
||||
import { namespaces } from './resources'
|
||||
|
||||
export function getInitOptions(): InitOptions {
|
||||
return {
|
||||
@@ -8,7 +8,7 @@ export function getInitOptions(): InitOptions {
|
||||
fallbackLng: 'en-US',
|
||||
partialBundledLanguages: true,
|
||||
keySeparator: false,
|
||||
ns: namespacesCamelCase,
|
||||
ns: namespaces,
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
},
|
||||
|
||||
7
web/types/i18n.d.ts
vendored
7
web/types/i18n.d.ts
vendored
@@ -1,17 +1,16 @@
|
||||
import type { NamespaceCamelCase, Resources } from '../i18n-config/resources'
|
||||
import type { Namespace, Resources } from '../i18n-config/resources'
|
||||
import 'i18next'
|
||||
|
||||
declare module 'i18next' {
|
||||
// eslint-disable-next-line ts/consistent-type-definitions
|
||||
interface CustomTypeOptions {
|
||||
defaultNS: 'common'
|
||||
resources: Resources
|
||||
keySeparator: false
|
||||
}
|
||||
}
|
||||
|
||||
export type I18nKeysByPrefix<
|
||||
NS extends NamespaceCamelCase,
|
||||
NS extends Namespace,
|
||||
Prefix extends string = '',
|
||||
> = Prefix extends ''
|
||||
? keyof Resources[NS]
|
||||
@@ -22,7 +21,7 @@ export type I18nKeysByPrefix<
|
||||
: never
|
||||
|
||||
export type I18nKeysWithPrefix<
|
||||
NS extends NamespaceCamelCase,
|
||||
NS extends Namespace,
|
||||
Prefix extends string = '',
|
||||
> = Prefix extends ''
|
||||
? keyof Resources[NS]
|
||||
|
||||
7
web/utils/object.ts
Normal file
7
web/utils/object.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export function ObjectFromEntries<const T extends ReadonlyArray<readonly [PropertyKey, unknown]>>(entries: T): { [K in T[number]as K[0]]: K[1] } {
|
||||
return Object.fromEntries(entries) as { [K in T[number]as K[0]]: K[1] }
|
||||
}
|
||||
|
||||
export function ObjectKeys<const T extends Record<string, unknown>>(obj: T): (keyof T)[] {
|
||||
return Object.keys(obj) as (keyof T)[]
|
||||
}
|
||||
Reference in New Issue
Block a user