前端国际化实战:从需求到落地的完整实践
"我们要开拓东南亚市场了!"产品经理小王兴奋地告诉我这个消息。作为技术负责人,我立刻意识到这意味着我们需要对整个系统进行国际化改造。说实话,虽然之前也做过一些多语言的项目,但面对一个正在运行的大型系统,国际化改造的挑战还是不小。
回想起上周的需求评审会,我们讨论了很多细节问题:不同语言的排版布局、日期时间格式、货币单位转换等等。经过一番头脑风暴,我们制定了一个详细的改造计划。今天就来分享这个过程中的实战经验。
需求分析
首先,我们需要明确国际化的具体需求。通过和产品、运营的深入沟通,我们确定了几个关键点:
第一个挑战是语言切换。系统要支持英语、泰语、越南语和印尼语,而且要能够根据用户的浏览器设置自动选择默认语言。"用户第一次访问时,要让他感觉这就是为他准备的。"产品经理特别强调这一点。
第二个挑战是内容适配。不同语言的文字长度差异很大,比如英文的"Submit"翻译成泰语后会长很多。而且有些语言还有特殊的书写方向和字体要求。
第三个挑战是本地化处理。日期、时间、货币这些格式在不同地区都有各自的规范。"不能让用户看到 2024/12/3,他们习惯的可能是 3/12/2024。"运营同学提醒道。
技术方案
经过调研,我们设计了一个灵活的国际化方案。就像搭建一个多语言的图书馆,我们需要有清晰的分类系统(语言配置),便捷的检索方式(语言切换),以及统一的管理制度(翻译流程)。
首先是语言包的组织方式:
// 按功能模块划分语言包
const messages = {en: {common: {submit: 'Submit',cancel: 'Cancel',confirm: 'Confirm'},auth: {login: 'Log In',register: 'Sign Up',forgotPassword: 'Forgot Password?'},dashboard: {welcome: 'Welcome back, {name}',totalUsers: '{count} users',activeToday: '{count} active today'}},th: {common: {submit: 'ส่ง',cancel: 'ยกเลิก',confirm: 'ยืนยัน'}// ... 其他泰语翻译}
}
然后是语言切换的核心逻辑:
// hooks/useI18n.ts
function useI18n() {const [locale, setLocale] = useState(() => {// 优先使用用户设置的语言const savedLocale = localStorage.getItem('locale')if (savedLocale) return savedLocale// 其次使用浏览器语言const browserLocale = navigator.language.split('-')[0]return supportedLocales.includes(browserLocale) ? browserLocale : 'en'})const formatMessage = useCallback((key: string, values?: Record<string, any>) => {const template = get(messages[locale], key, key)if (!values) return templatereturn template.replace(/\{(\w+)\}/g, (_, key) => values[key] || '')},[locale])const changeLocale = useCallback((newLocale: string) => {if (!supportedLocales.includes(newLocale)) returnsetLocale(newLocale)localStorage.setItem('locale', newLocale)// 更新 HTML 的 lang 属性document.documentElement.lang = newLocale// 更新 moment 的语言设置moment.locale(newLocale)}, [])return { locale, formatMessage, changeLocale }
}
对于日期和货币的处理,我们使用了专门的库:
// utils/formatter.ts
import { format } from 'date-fns'
import * as locales from 'date-fns/locale'export function formatDate(date: Date, locale: string) {const dateLocale = locales[locale] || locales.enUSreturn format(date, 'PPP', { locale: dateLocale })
}export function formatCurrency(amount: number, locale: string) {return new Intl.NumberFormat(locale, {style: 'currency',currency: getCurrencyByLocale(locale)}).format(amount)
}// 根据语言获取对应的货币
function getCurrencyByLocale(locale: string) {const currencyMap = {en: 'USD',th: 'THB',vi: 'VND',id: 'IDR'}return currencyMap[locale] || 'USD'
}
实践细节
在实际开发中,我们遇到了一些有趣的挑战。比如泰语的字体渲染问题,我们通过动态加载字体来解决:
// 动态加载字体
const loadFont = async (locale: string) => {const fontMap = {th: 'https://fonts.googleapis.com/css2?family=Noto+Sans+Thai&display=swap',vi: 'https://fonts.googleapis.com/css2?family=Noto+Sans+Vietnamese&display=swap'}if (!fontMap[locale]) returnconst link = document.createElement('link')link.rel = 'stylesheet'link.href = fontMap[locale]document.head.appendChild(link)
}
为了提高翻译的效率,我们开发了一个翻译管理平台,支持在线编辑和自动同步:
// 翻译同步服务
async function syncTranslations() {// 获取所有需要翻译的文本const texts = await extractTextsFromCode()// 对比已有翻译,找出缺失的部分const missingTranslations = findMissingTranslations(texts)// 使用翻译服务进行翻译const translations = await translateTexts(missingTranslations)// 更新语言包await updateLanguageFiles(translations)
}
效果验证
改造完成后,我们进行了全面的测试:
- 不同语言环境下的页面布局
- 各种日期和货币格式的显示
- 动态切换语言的性能
- 特殊字符的渲染
最让我印象深刻的是一位泰国用户的反馈:"感觉就像在用本地开发的应用一样自然。"这正是我们想要达到的效果。
经验总结
国际化改造的过程让我们学到了很多。就像装修一座老房子,你需要在不影响居住的情况下,把每个房间都改造成适合不同人居住的样子。这个过程需要:
细致的规划 - 就像要先确定每个房间的用途灵活的设计 - 能适应不同人的生活习惯周到的考虑 - 照顾到每个细节的体验
写在最后
前端国际化不仅仅是翻译文本,更是一次全方位的用户体验提升。正如那句话说的:"Think globally, act locally"(全球思维,本地行动),我们要在保持产品统一性的同时,让每个地区的用户都能获得最自然的使用体验。
有什么问题欢迎在评论区讨论,让我们一起探讨国际化实践的经验!
如果觉得有帮助,别忘了点赞关注,我会继续分享更多实战经验~
相关文章:
前端国际化实战:从需求到落地的完整实践
"我们要开拓东南亚市场了!"产品经理小王兴奋地告诉我这个消息。作为技术负责人,我立刻意识到这意味着我们需要对整个系统进行国际化改造。说实话,虽然之前也做过一些多语言的项目,但面对一个正在运行的大型系统,国际化改造的挑战还是不小。 回想起上周的…...
React的状态管理库-Redux
核心思想:单一数据源、状态是只读的、以及使用纯函数更新状态。 组成部分 Store(存储) 应用的唯一状态容器,存储整个应用的状态树,使用 createStore() 创建。 getState():获取当前状态。dispatch(action)ÿ…...
【Android学习】RxJava
文章目录 资料连接1. Merge & Zip操作符: 合并数据源2. Map & FlapMap & ConcatMap & Buffer: 变换操作符3. retry & retryUntil & retryWhen : 错误处理操作符4. Transformer & Compose 转换符 资料连接 Android RxJava: 这是一份全面…...
Pycharm访问MySQL数据库·上
1.MySQL驱动模块Connector #导入数据库的驱动工具 import mysql.connector #连接数据库必备的条件 config {"host": "localhost","port": 3306,"user": "root","password": "888888","database&…...
【CUDA】CUBLAS
【CUDA】CUBLAS 在深入了解之前,提前运行预热(warmup)和基准测试(benchmark runs) 是获得准确执行时间的关键。如果不进行预热运行,cuBLAS 的首次运行会有较大的开销(大约 45 毫秒)…...
YOLOv8-ultralytics-8.2.103部分代码阅读笔记-predict.py
predict.py ultralytics\models\yolo\detect\predict.py 目录 predict.py 1.所需的库和模块 2.class DetectionPredictor(BasePredictor): 1.所需的库和模块 # Ultralytics YOLO 🚀, AGPL-3.0 licensefrom ultralytics.engine.predictor import BasePredicto…...
细说Flash存储芯片W25Q128FW和W25Q16BV
目录 一、Flash存储芯片W25Q128FW 1、W25Q128硬件接口和连接 2、存储空间划分 3、数据读写的原则 4、操作指令 (1)“写使能”指令 (2)“读数据”指令 (3)“写数据”指令 5、状态寄存器SR1 二、Fl…...
python爬虫--小白篇【爬取B站视频】
目录 一、任务分析 二、网页分析 三、任务实现 一、任务分析 将B站视频爬取并保存到本地,经过分析可知可以分为四个步骤,分别是: 爬取视频页的网页源代码;提取视频和音频的播放地址;下载并保存视频和音频&#x…...
Three.js入门-模型加载
Three.js 支持多种 3D 模型格式,每种格式有其独特的优势和适用场景。根据项目的需求,选择合适的格式可以提高开发效率和用户体验。下面将详细介绍几种常见的模型格式及其特点,并补充每种格式的典型使用场景。 支持的模型类型及特点 Three.j…...
ECharts实现数据可视化入门详解
文章目录 ECharts实现数据可视化入门详解一、引言二、基础配置1.1、代码示例 三、动态数据与交互2.1、代码示例 四、高级用法1、多图表组合1.1、在同一容器中绘制多个图表1.2、创建多个容器并分别初始化 ECharts 实例1.3、实现多图联动 五、总结 ECharts实现数据可视化入门详解…...
C++(举例说明类的实例化方式)
太多的信息会让你抓不住重点,下面通过间短的举例说明了类的几种实例化方式,熟悉以后再阅读代码的时候就能减少疑惑。 1.直接实例化:使用类名直接实例化对象 MyClass obj; 2.使用 new 关键字动态分配内存:使用 new 关键字来在堆上…...
LeetCode32. 最长有效括号(2024冬季每日一题 32)
给你一个只包含 ( 和 ) 的字符串,找出最长有效(格式正确且连续)括号子串的长度。 示例 1: 输入:s “(()” 输出:2 解释:最长有效括号子串是 “()” 示例 2: 输入:s “…...
Textfocals ——基于大言模型的用户驱动型文本改进工具让用户在审阅自己的写作时对其进行修改
概述 论文地址:https://arxiv.org/abs/2403.01055 大规模语言模型可以生成媲美专业作家撰写的文本。目前使用的对话技术主要有两种:一种是交互式(如 OpenAI 的 ChatGPT 和 Google 的 Gemini),另一种是预测性文本补全&…...
docker 部署 redis
docker 部署 redis 1. 下载 redis 镜像 # docker images | grep redis bitnami/redis 7.2.4-debian-11-r5 45de196aef7e 10 months ago 95.2MB2. docker-compose 部署 version: "3" services:redis:image: bitnami/redis:7.2.4-debian-11-…...
微信小程序横屏页面跳转后,自定义navbar样式跑了?
文章目录 问题原因:解决方案: 今天刚遇到的问题,横屏的页面完成操作后跳转页面后,自定义的tabbar样式乱了,跑到最顶了,真机调试后发现navbar跑到手机状态栏了,它正常应该跟右边胶囊一行。 知道问…...
回归预测 | MATLAB实现BiGRU(双向门控循环单元)多输入单输出
回归预测 | MATLAB实现BiGRU(双向门控循环单元)多输入单输出 文章目录 回归预测 | MATLAB实现BiGRU(双向门控循环单元)多输入单输出预测效果基本介绍程序设计参考资料致谢预测效果 基本介绍 BiGRU(双向门控循环单元)多输入单输出模型是一种结合了双向门控循环单元(BiGRU)的…...
智能时代的基石:神经网络
智能时代的基石:神经网络 第一节:神经网络简介 课程目标 本节课程旨在全面介绍神经网络的基本概念、结构以及其在历史发展中的重要里程碑。通过深入理解神经网络的工作原理和演变过程,学员将能够掌握神经网络在现实世界中的多种应用&#…...
红与黑,,
有一间长方形的房子,地上铺了红色、黑色两种颜色的正方形瓷砖。 你站在其中一块黑色的瓷砖上,只能向相邻(上下左右四个方向)的黑色瓷砖移动。 请写一个程序,计算你总共能够到达多少块黑色的瓷砖。 输入格式 输入包…...
嵌入式驱动开发详解16(音频驱动开发)
文章目录 前言WM8960简介I2S协议接口说明 SAI音频接口简介驱动框架简介设备树配置内核使能声卡设置与测试 后续参考文献 前言 该专栏主要是讲解嵌入式相关的驱动开发,但是由于ALSA驱动框架过于复杂,实现音频编解码芯片的驱动不是一个人能完成的…...
【嵌入式软件】跑开发板的前置服务配置
在嵌入式开发中,通常需要在 开发板和主机之间共享、传输和挂载文件。 这篇文章是关于如何在 Ubuntu 中配置 Samba、TFTP 和 NFS 协议的详细步骤。这些协议分别用于远程文件共享、文件传输和内核挂载文件系统。 如何安装协议: 参考:ubuntu18配置:详细的内容我手写了一份文档。…...
为AI智能体项目选择与接入高性价比大模型API服务
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 为AI智能体项目选择与接入高性价比大模型API服务 在构建AI智能体或自动化工作流时,开发者面临的核心挑战往往集中在两个…...
Python机器学习实战路线图:从EDA到模型部署的工业级路径
1. 这不是“速成课”,而是一份我带过37个转行学员后重写的Python机器学习实战路线图 你点开这篇,大概率正站在两个路口之间:一边是刷了三个月Kaggle入门赛却卡在特征工程上动弹不得,另一边是翻烂了《统计学习方法》却连一个能跑通…...
手把手教你从零搭建 MCP Server:AI 连接万物的保姆级实战教程
为什么要学 MCP? 说实话,最近半年 AI 开发圈最火的协议就是 MCP(Model Context Protocol)了。你可能已经用上了各种 AI 助手,但有没有想过:这些 AI 怎么连接你的数据库?怎么读你的本地文件&…...
传统开发VS低代码开发,谁更胜一筹?
低代码开发,让企业应用搭建像搭积木一样简单 在当今数字化时代,企业对于应用程序的需求日益增长。然而,传统的软件开发方式往往面临着开发周期长、成本高、技术门槛高等问题,这使得许多企业在数字化转型的道路上举步维艰。而低代…...
Unity资源提取原理与uTinyRipper实战指南
1. 为什么你第一次打开uTinyRipper时会“卡在加载界面”——这不是软件坏了,是Unity资源结构在对你说话 “零基础入门:uTinyRipper Unity资产提取完全指南”这个标题里藏着一个被绝大多数新手忽略的关键前提: uTinyRipper不是万能解包器&…...
手机提取OTA镜像文件:无需电脑的Android系统镜像提取终极指南
手机提取OTA镜像文件:无需电脑的Android系统镜像提取终极指南 【免费下载链接】Payload-Dumper-Android Payload Dumper App for Android. Extract boot.img or any other partitions (images) from OTA.zip or payload.bin without PC 项目地址: https://gitcode…...
RabbitMQ 入门与安装
RabbitMQ 入门与安装:从 MQ 概念到环境搭建 一、开篇:学习 RabbitMQ 前需要准备什么 RabbitMQ 属于消息中间件,是 Java 后端开发中非常常见的一类基础组件。学习它之前,最好已经具备以下基础: 具备一定 Java 基础&…...
为什么选择Minimal:GitHub Pages最简洁主题的深度解析与快速入门指南
为什么选择Minimal:GitHub Pages最简洁主题的深度解析与快速入门指南 【免费下载链接】minimal Minimal is a Jekyll theme for GitHub Pages 项目地址: https://gitcode.com/gh_mirrors/mini/minimal Minimal主题是GitHub Pages平台上最受欢迎、最简洁的Jek…...
【DeepSeek事实准确性测试权威报告】:2024年7大维度实测数据揭穿幻觉率真相
更多请点击: https://intelliparadigm.com 第一章:DeepSeek事实准确性测试权威报告总览 本报告基于2024年Q3由AI Safety Benchmark Consortium(ASBC)主导的跨模型事实一致性评估项目,对DeepSeek-V2、DeepSeek-Coder-3…...
5分钟快速获取微信数据库密钥:Sharp-dumpkey完整使用指南
5分钟快速获取微信数据库密钥:Sharp-dumpkey完整使用指南 【免费下载链接】Sharp-dumpkey 基于C#实现的获取微信数据库密钥的小工具 项目地址: https://gitcode.com/gh_mirrors/sh/Sharp-dumpkey 你是否曾因为无法访问自己的微信聊天记录而感到困扰ÿ…...
