React多语言自定义Hook如何在客户端读取Next.js public目录下的JSON文件
问题原因分析
- 你的当前代码仅在Node.js服务端环境(
typeof window === 'undefined')执行了读取逻辑,浏览器客户端环境下该分支不会执行,LanguagesFile变量默认为undefined fs是Node.js专属的文件系统API,浏览器端不存在该能力,无法用fs读取本地项目文件- Next.js的
public目录下的静态资源会直接暴露在服务的根路由下,客户端可以通过HTTP请求直接获取
修复方案
第一步:将语言文件加载逻辑迁移到LanguageProvider
统一在上下文层处理服务端、客户端的加载逻辑,避免重复加载,修改后代码示例:
'use client' // Next.js App Router 环境需要添加该指令 import { createContext, useContext, useState, useEffect } from 'react' const LanguageContext = createContext({ locale: 'zh-CN', languageData: {}, setLocale: (locale: string) => {} }) export function LanguageProvider({ children, defaultLocale = 'zh-CN' }) { const [locale, setLocale] = useState(defaultLocale) const [languageData, setLanguageData] = useState({}) // 服务端直接读取文件 if (typeof window === 'undefined') { const fs = require('fs') const fileContent = fs.readFileSync('./public/Languages.json', 'utf8') setLanguageData(JSON.parse(fileContent)) } // 客户端通过请求获取静态资源 useEffect(() => { const fetchLanguages = async () => { try { const res = await fetch('/Languages.json') const data = await res.json() setLanguageData(data) } catch (e) { console.error('加载语言文件失败,请检查public目录下是否存在Languages.json', e) } } // 避免hydration时服务端和客户端数据不一致,客户端仅在没有数据时请求 if (Object.keys(languageData).length === 0) { fetchLanguages() } }, [languageData]) return ( <LanguageContext.Provider value={{ locale, setLocale, languageData }}> {children} </LanguageContext.Provider> ) }
第二步:简化useTranslation逻辑
直接从上下文取已经加载完成的语言数据,不需要处理加载逻辑,同时修正原代码的判断逻辑错误:
import { useContext } from 'react' import { LanguageContext } from './LanguageProvider' export function useTranslation() { const { locale, languageData } = useContext(LanguageContext) function t(key: string) { if (!languageData?.[locale]?.[key]) { console.warn(`No string '${key}' for locale '${locale}'`) return key // 找不到的时候返回key作为兜底,比返回false更友好 } return languageData[locale][key].toString() || '' } return { t, locale } }
额外优化建议
- 可以给npm包增加配置项,支持用户自定义语言文件的路径,不要硬编码
/Languages.json - 可以增加语言切换时的热加载能力,切换locale不需要刷新页面
- 可以添加类型支持,根据用户的Languages.json生成key的类型提示,提升开发体验
内容的提问来源于stack exchange,提问作者Mohammad Naderi
相关产品推荐
相关产品推荐

