您现在的位置是:网站首页 > 国际化实现文章详情
国际化实现
陈川
【
ECharts
】
24387人已围观
8304字
国际化实现
ECharts 的国际化支持让图表能够适应不同语言环境的需求。通过配置语言和地区参数,开发者可以轻松实现图表文本、提示框、图例等内容的本地化展示。国际化功能覆盖了组件文本、时间格式化、数值格式化等多个方面,为全球用户提供一致的体验。
语言包配置
ECharts 内置了多种语言包,包括中文(简体/繁体)、英文、日文等。使用前需要注册对应的语言包:
// 引入ECharts和语言包
import * as echarts from 'echarts';
import 'echarts/i18n/langEN'; // 英文
import 'echarts/i18n/langJA'; // 日文
// 注册语言
echarts.registerLocale('EN', require('echarts/i18n/langEN').default);
echarts.registerLocale('JA', require('echarts/i18n/langJA').default);
初始化图表时指定语言:
const chart = echarts.init(document.getElementById('chart'), null, {
locale: 'EN' // 使用英文
});
组件文本国际化
所有可视化组件都支持国际化,包括标题、图例、坐标轴等:
option = {
title: {
text: 'Sales Report' // 文本会根据语言包自动转换
},
tooltip: {
trigger: 'axis'
},
legend: {
data: ['Sales', 'Cost'] // 图例项也会被翻译
},
xAxis: {
type: 'category',
data: ['Jan', 'Feb', 'Mar']
},
yAxis: {
type: 'value'
}
};
时间格式化
时间轴的显示会根据语言环境自动调整格式:
option = {
xAxis: {
type: 'time',
axisLabel: {
formatter: '{yyyy}-{MM}-{dd}' // 格式会自动适配地区习惯
}
},
series: [{
data: [
['2023-01-01', 100],
['2023-01-02', 200]
],
type: 'line'
}]
};
数值格式化
数值显示支持地区差异,如千分位分隔符和小数点:
option = {
tooltip: {
formatter: '{b}: {c}' // 数值会根据地区自动格式化
},
series: [{
data: [1200.5, 2000.8, 1500.3],
type: 'bar'
}]
};
自定义语言包
当内置语言包不满足需求时,可以创建自定义语言包:
const customLocale = {
time: {
month: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
monthAbbr: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
dayOfWeek: ['日', '一', '二', '三', '四', '五', '六'],
dayOfWeekAbbr: ['日', '一', '二', '三', '四', '五', '六']
},
legend: {
scroll: '滚动',
selectAll: '全选'
}
};
echarts.registerLocale('custom', customLocale);
动态切换语言
实现运行时语言切换需要销毁并重新初始化图表:
function changeLanguage(lang) {
const container = document.getElementById('chart');
const oldChart = echarts.getInstanceByDom(container);
if (oldChart) {
oldChart.dispose();
}
const newChart = echarts.init(container, null, {
locale: lang
});
newChart.setOption(option);
}
// 切换按钮事件
document.getElementById('btn-en').addEventListener('click', () => changeLanguage('EN'));
document.getElementById('btn-ja').addEventListener('click', () => changeLanguage('JA'));
多语言图表组合
同一个页面可以展示不同语言的多个图表:
// 英文图表
const chartEN = echarts.init(document.getElementById('chart-en'), null, {
locale: 'EN'
});
chartEN.setOption(option);
// 日文图表
const chartJA = echarts.init(document.getElementById('chart-ja'), null, {
locale: 'JA'
});
chartJA.setOption(option);
服务端渲染的国际化
对于SSR场景,需要在服务端设置语言环境:
// Node.js 服务端代码
const echarts = require('echarts');
require('echarts/i18n/langEN');
const option = {
title: {
text: 'Server-side Chart'
}
};
const chartHTML = echarts.renderToString(option, {
locale: 'EN',
width: 600,
height: 400
});
第三方组件集成
当ECharts与其他UI库配合使用时,确保语言环境一致:
// 使用Vue-ECharts示例
<template>
<v-chart :option="option" :init-options="{ locale: currentLang }" />
</template>
<script>
import { use } from 'echarts/core';
import { CanvasRenderer } from 'echarts/renderers';
import 'echarts/i18n/langEN';
export default {
data() {
return {
currentLang: 'EN',
option: {
title: { text: 'Vue Chart' }
}
}
}
}
</script>
无障碍访问
国际化还应考虑无障碍需求,为屏幕阅读器提供支持:
option = {
aria: {
enabled: true,
label: {
description: 'This is a bar chart showing monthly sales data'
}
}
};
本地化扩展
除了文本翻译,还可以扩展本地化功能:
// 扩展货币符号显示
echarts.registerLocale('EN-US', {
...require('echarts/i18n/langEN').default,
currency: {
symbol: '$',
symbolPosition: 'before',
decimal: '.',
thousand: ','
}
});
// 在tooltip中使用
option = {
tooltip: {
formatter: (params) => {
const value = params[0].value;
return `${params[0].name}: ${value.toLocaleString('en-US')}$`;
}
}
};
时区处理
对于跨时区应用,需要正确处理时间显示:
option = {
xAxis: {
type: 'time',
axisLabel: {
formatter: (value) => {
return echarts.format.formatTime('yyyy-MM-dd HH:mm', value, false, 'America/New_York');
}
}
}
};
复杂文本处理
处理从右到左(RTL)语言布局:
// 阿拉伯语等RTL语言支持
echarts.registerLocale('AR', {
...require('echarts/i18n/langAR').default,
direction: 'rtl'
});
const chart = echarts.init(document.getElementById('chart'), null, {
locale: 'AR'
});
// 需要额外调整的样式
option = {
grid: {
right: '10%',
left: '30%' // RTL语言通常需要调整布局
}
};
性能优化
多语言场景下的性能考虑:
// 按需加载语言包
async function loadChart(lang) {
const locale = await import(`echarts/i18n/lang${lang.toUpperCase()}`);
echarts.registerLocale(lang, locale.default);
const chart = echarts.init(document.getElementById('chart'), null, { locale: lang });
chart.setOption(option);
}
// 使用Webpack的魔法注释实现预加载
import(/* webpackPrefetch: true */ `echarts/i18n/lang${userLang.toUpperCase()}`);
错误处理
处理语言包加载失败的情况:
try {
const locale = await import(`echarts/i18n/lang${lang}`);
echarts.registerLocale(lang, locale.default);
} catch (e) {
console.warn(`Language pack for ${lang} not found, falling back to EN`);
const locale = await import('echarts/i18n/langEN');
echarts.registerLocale('EN', locale.default);
lang = 'EN';
}
测试验证
确保国际化功能正确实现的测试方法:
// 使用Jest测试不同语言环境
describe('ECharts Internationalization', () => {
test('should display English labels', () => {
const chart = initChart('EN');
expect(chart.getOption().title.text).toBe('Sales Report');
});
test('should display Japanese labels', () => {
const chart = initChart('JA');
expect(chart.getOption().title.text).toBe('売上レポート');
});
});
持续集成
在多语言项目中的CI/CD流程集成:
# .github/workflows/test.yml
jobs:
test:
strategy:
matrix:
lang: [EN, JA, ZH]
steps:
- run: npm test -- --lang=${{ matrix.lang }}
用户偏好保存
记住用户的语言选择:
// 从本地存储获取用户偏好
const userLang = localStorage.getItem('preferredLang') || navigator.language.slice(0, 2).toUpperCase();
// 初始化图表
const chart = echarts.init(document.getElementById('chart'), null, {
locale: ['EN', 'JA'].includes(userLang) ? userLang : 'EN'
});
// 保存用户选择
function setLanguage(lang) {
localStorage.setItem('preferredLang', lang);
changeLanguage(lang);
}
框架集成示例
与React集成的完整示例:
import React, { useEffect, useRef } from 'react';
import * as echarts from 'echarts';
import 'echarts/i18n/langEN';
import 'echarts/i18n/langJA';
function ChartComponent({ language }) {
const chartRef = useRef(null);
let chartInstance = null;
useEffect(() => {
const initChart = () => {
if (chartInstance) {
chartInstance.dispose();
}
chartInstance = echarts.init(chartRef.current, null, {
locale: language
});
chartInstance.setOption({
title: { text: 'React Chart' },
series: [{ type: 'bar', data: [100, 200, 150] }]
});
};
initChart();
return () => {
if (chartInstance) {
chartInstance.dispose();
}
};
}, [language]);
return <div ref={chartRef} style={{ width: '100%', height: '400px' }} />;
}
企业级应用实践
大型项目中的国际化架构设计:
// 国际化模块封装
class ChartI18n {
constructor() {
this.currentLang = 'EN';
this.loadedLanguages = new Set(['EN']);
}
async setLanguage(lang) {
if (!this.loadedLanguages.has(lang)) {
try {
const locale = await import(`echarts/i18n/lang${lang}`);
echarts.registerLocale(lang, locale.default);
this.loadedLanguages.add(lang);
} catch (e) {
console.error(`Failed to load language ${lang}`, e);
lang = 'EN';
}
}
this.currentLang = lang;
}
getInstance(dom, option) {
return echarts.init(dom, null, {
locale: this.currentLang
});
}
}
// 应用中使用
const chartI18n = new ChartI18n();
await chartI18n.setLanguage(userLang);
const chart = chartI18n.getInstance(document.getElementById('chart'));
chart.setOption(option);