此笔记是基于开发 Plumbiu/nextjs_tensorflow 时所遇到的问题而总结的
本次项目较小,采用的国际化方案比较简单,如果是大一点的项目,可以尝试以下官方推荐的包:
react-intl
, react-i18next
, lingui
, rosetta
, next-intl
, next-translate
, next-multilingual
, typesafe-i18n
,
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
i18n: {
locales: ['en-US', 'zh-CN'],
defaultLocale: 'zh-CN'
}
}
配置好 next.config.js
文件对应的 i18n
后,我们可以在组件中访问到对应的 locales
和 locale
const { locales. locale } = useRouter()
console.log(locales) // ['zh-CN', 'zh-CN']
console.log(locale) // 'zh-CN'
其中 locales
为我们配置好的几种语言,locale
为当前所处语言
切换可以使用以下方法
Link
标签:增加 locale
属性即可
export default function page() {
return (
<Link href='/another' locale="en-US">
To en-us
</Link>
)
}
router.push
方法:有点意思的是,router.push
可以接受三个参数:
as
官方解释为连接伪装(url masking
),locale
属性export default function page() {
const router = useRouter()
function localeChangeHandler(locale) {
router.push(router.pathname, router.asPath, {
locale
})
}
return (
<button onClick={() => localeChangeHandler('en-US')}>
English
</button>
)
}
URL masking,也称为链接伪装,是URL重定向的一种形式。URL重定向是将您的域名访问者发送到另一个备用目标URL。掩码重定向也称为URL伪装或域名掩码。掩码(或外套)指的是地址栏中的URL不是页面上内容的实际URL。因此,您的用户认为他们在一个域上,而实际上他们在另一个域上。
此时,如果我们切换 locale
,路由的地址也会发生变化,这是 NextJS
预先配置好的
对于默认语言(本项目中为 zh-CN
),路由地址为 127.0.0.1/xxx
对于 en-US
,路由地址为 127.0.0.1/en-US/xxx
我们需要准备类似以下格式的 json
文件,用于 en-US
和 zh-CN
语言的切换:
{
"en-US": {
"bar": "This is bar's title"
},
"zh-CN": {
"bar": "这是 bar 的标题"
}
}
// 1. 导入对应的 json 文件
import i18n from '@/assets/title.json'
export default function page() {
// 2. 获取当前浏览器的语言
const { locale } = useRouter()
return (
{/* 3. 对应数据的写法 */}
<h2>{i18n[locale]['bar']}</h2>
)
}
html 中的 input[type=file]
的默认样式太难看,而且无法更改样式:
对此,我们可以曲线修改,也就是用 <button>
实现:
export default function page() {
const iptRef = useRef(null)
function fileHandler() {
if(!prtRef.current || !iptRef.current.files) return
const file = iptRef.current.files[0]
// ...
}
return (
<>
<input ref={iptRef} onChange={fileHandler} type="file" hidden />
<button onClick={() => iptRef.current.click()}>上传文件</button>
</>
)
}
分析上面代码,核心包括以下几点:
input[type=file]
添加 hidden
属性即可
<input hidden type='file' />
input[type=file]
的点击事件<button onClick={() => iptRef.current.click() }>
上传文件
</button>
input[type=file]
的 onChange
属性<input hidden type='file' onChange={fileHandler} />
fileHandler
function fileHandler() {
if(!iptRef.current || !iptRef.current.files) return
const file = iptRef.current.files[0]
// do something
}
可以使用 window.URL.createObjectURL(file: File)
创建一个 唯一的 blob 连接用于显示
注:只是在前端页面展示,并不是上传图片到后端
export default function page() {
const [imgSrc, setImgSrc] = useState('')
const iptRef = useRef(null)
function imgShowHandler() {
if(!(iptRef.current && ipt.current.files)) return
const file = iptRef.current.files[0]
setImgSrc(window.URL.createObjectURL(file))
}
return (
<div>
{ imgSrc ? <img src={imgSrc} /> : <p>Empty Img</p> }
<input onChange={imgShowHandler} ref={iptRef} hidden type="file" accept="image/png,image/jpg" />
<button onClick={() => iptRef.current.click()}>上传图片</button>
</div>
)
}
核心逻辑代码:
img
的链接const [imgSrc, setImgSrc] = useState('')
// ...
return (
<img src={imgSrc} />
)
img
链接使用 window.URL.createObjectURL(file)
即可
function imgShowHandler() {
// 如果 input 标签实例或者文件未上传不存在,那么不作任何处理
if(!(iptRef.current && iptRef.current.files)) return
// 此 demo 演示的是单文件上传,所以获取 files 的第一个元素
const file = iptRef.current.files[0]
// 使用 window.URL.createObjectURL(file) 创建对应图片的一个唯一 blob 标签, 并将其设置成 img
setImgSrc(window.URL.createObjectURL(file))
}