温馨提示:本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦!
HarmonyOS NEXT 应用国际化与本地化指南:打造全球化应用
1. 国际化基础
1.1 基本概念
概念 | 说明 | 实现方式 | 示例 |
---|---|---|---|
国际化(i18n) | 支持多语言 | 文本翻译 | 中英文切换 |
本地化(l10n) | 适应地区 | 格式适配 | 日期格式 |
区域设置 | 地区配置 | 系统设置 | zh-CN, en-US |
1.2 国际化配置
// i18n.config.ts
interface I18nConfig {
defaultLocale: string;
supportedLocales: string[];
fallbackLocale: string;
loadPath: string;
}
class I18nManager {
private static instance: I18nManager;
private config: I18nConfig;
private translations: Map<string, any> = new Map();
private currentLocale: string;
private constructor() {
this.config = {
defaultLocale: 'en-US',
supportedLocales: ['en-US', 'zh-CN', 'ja-JP'],
fallbackLocale: 'en-US',
loadPath: '/resources/i18n/'
};
}
static getInstance(): I18nManager {
if (!this.instance) {
this.instance = new I18nManager();
}
return this.instance;
}
// 初始化国际化
async initialize(): Promise<void> {
// 加载系统语言设置
this.currentLocale = await this.getSystemLocale();
// 加载翻译资源
await this.loadTranslations(this.currentLocale);
}
// 切换语言
async changeLocale(locale: string): Promise<void> {
if (!this.config.supportedLocales.includes(locale)) {
throw new Error(`Unsupported locale: ${locale}`);
}
this.currentLocale = locale;
await this.loadTranslations(locale);
this.notifyLocaleChange();
}
}
2. 多语言支持
2.1 翻译资源管理
// translations.ts
interface TranslationResource {
[key: string]: string | TranslationResource;
}
class TranslationManager {
private resources: Map<string, TranslationResource> = new Map();
// 加载翻译资源
async loadResources(locale: string): Promise<void> {
try {
const resource = await this.fetchTranslations(locale);
this.resources.set(locale, resource);
} catch (error) {
console.error(`Failed to load translations for ${locale}:`, error);
throw error;
}
}
// 获取翻译文本
translate(
key: string,
params?: object,
locale?: string
): string {
const currentLocale = locale || I18nManager.getInstance().currentLocale;
const resource = this.resources.get(currentLocale);
if (!resource) {
return key;
}
let value = this.getNestedValue(resource, key);
if (typeof value !== 'string') {
return key;
}
// 替换参数
if (params) {
value = this.interpolateParams(value, params);
}
return value;
}
// 参数插值
private interpolateParams(
text: string,
params: object
): string {
return text.replace(/\{(\w+)\}/g, (_, key) =>
params[key]?.toString() || ''
);
}
}
2.2 组件国际化
// i18n.component.ets
@Component
struct I18nText {
@State text: string = '';
private key: string;
private params?: object;
aboutToAppear() {
// 监听语言变化
this.updateText();
I18nManager.getInstance().onLocaleChange(() => {
this.updateText();
});
}
private updateText() {
this.text = TranslationManager.getInstance()
.translate(this.key, this.params);
}
build() {
Text(this.text)
}
}
// 使用示例
@Component
struct WelcomeScreen {
build() {
Column() {
I18nText({
key: 'welcome.title',
params: { name: 'User' }
})
I18nText({
key: 'welcome.message'
})
}
}
}
3. 本地化适配
3.1 日期时间格式化
class DateTimeFormatter {
private locale: string;
constructor(locale: string) {
this.locale = locale;
}
// 格式化日期
formatDate(
date: Date,
format?: Intl.DateTimeFormatOptions
): string {
const options = format || {
year: 'numeric',
month: 'long',
day: 'numeric'
};
return new Intl.DateTimeFormat(
this.locale,
options
).format(date);
}
// 格式化时间
formatTime(
date: Date,
format?: Intl.DateTimeFormatOptions
): string {
const options = format || {
hour: 'numeric',
minute: 'numeric',
hour12: true
};
return new Intl.DateTimeFormat(
this.locale,
options
).format(date);
}
// 格式化相对时间
formatRelative(date: Date): string {
const rtf = new Intl.RelativeTimeFormat(this.locale, {
numeric: 'auto'
});
const diff = date.getTime() - Date.now();
const days = Math.round(diff / (1000 * 60 * 60 * 24));
return rtf.format(days, 'day');
}
}
3.2 数字和货币格式化
class NumberFormatter {
private locale: string;
constructor(locale: string) {
this.locale = locale;
}
// 格式化数字
formatNumber(
value: number,
options?: Intl.NumberFormatOptions
): string {
return new Intl.NumberFormat(
this.locale,
options
).format(value);
}
// 格式化货币
formatCurrency(
value: number,
currency: string
): string {
return new Intl.NumberFormat(this.locale, {
style: 'currency',
currency
}).format(value);
}
// 格式化百分比
formatPercent(value: number): string {
return new Intl.NumberFormat(this.locale, {
style: 'percent'
}).format(value);
}
}
4. 资源管理
4.1 多语言资源管理
class ResourceManager {
private static readonly RESOURCE_PATH = '/resources';
private resources: Map<string, any> = new Map();
// 加载资源
async loadResources(locale: string): Promise<void> {
try {
// 加载字符串资源
const strings = await this.loadStrings(locale);
// 加载图片资源
const images = await this.loadImages(locale);
// 加载其他资源
const others = await this.loadOtherResources(locale);
this.resources.set(locale, {
strings,
images,
others
});
} catch (error) {
console.error(`Failed to load resources for ${locale}:`, error);
throw error;
}
}
// 获取资源
getResource(
key: string,
type: string,
locale?: string
): any {
const currentLocale = locale || I18nManager.getInstance().currentLocale;
const resources = this.resources.get(currentLocale);
if (!resources || !resources[type]) {
return null;
}
return resources[type][key];
}
}
4.2 资源加载优化
class ResourceLoader {
private static cache: Map<string, any> = new Map();
// 预加载资源
static async preloadResources(
locale: string
): Promise<void> {
const resources = [
this.preloadStrings(locale),
this.preloadImages(locale),
this.preloadFonts(locale)
];
await Promise.all(resources);
}
// 懒加载资源
static async lazyLoadResource(
key: string,
type: string,
locale: string
): Promise<any> {
const cacheKey = `${locale}:${type}:${key}`;
if (this.cache.has(cacheKey)) {
return this.cache.get(cacheKey);
}
const resource = await this.loadResource(key, type, locale);
this.cache.set(cacheKey, resource);
return resource;
}
}
5. 最佳实践
5.1 国际化组件封装
// i18n.decorator.ts
function I18n(options: I18nOptions = {}) {
return function (target: any) {
return class extends target {
private i18n = I18nManager.getInstance();
aboutToAppear() {
// 监听语言变化
this.i18n.onLocaleChange(() => {
this.updateI18n();
});
if (super.aboutToAppear) {
super.aboutToAppear();
}
}
private updateI18n() {
// 更新组件的国际化文本
if (options.props) {
options.props.forEach(prop => {
if (this[prop]) {
this[prop] = this.i18n.translate(this[prop]);
}
});
}
}
}
}
}
// 使用示例
@I18n({
props: ['title', 'message']
})
@Component
struct LocalizedComponent {
@State title: string = 'welcome.title';
@State message: string = 'welcome.message';
build() {
Column() {
Text(this.title)
Text(this.message)
}
}
}
5.2 本地化测试
class LocalizationTester {
// 测试翻译完整性
static async testTranslations(
locales: string[]
): Promise<TestResult> {
const results = [];
for (const locale of locales) {
const missing = await this.findMissingTranslations(locale);
results.push({
locale,
missing,
complete: missing.length === 0
});
}
return {
success: results.every(r => r.complete),
results
};
}
// 测试格式化
static async testFormatting(
locale: string
): Promise<TestResult> {
const tests = [
this.testDateFormatting(locale),
this.testNumberFormatting(locale),
this.testCurrencyFormatting(locale)
];
const results = await Promise.all(tests);
return {
success: results.every(r => r.success),
results
};
}
}
5.3 最佳实践建议
文本管理
- 使用键值对管理文本
- 避免硬编码字符串
- 维护统一的翻译文件
资源组织
- 按语言分类资源
- 实现资源懒加载
- 优化资源加载性能
格式适配
- 使用标准格式化工具
- 考虑不同地区习惯
- 处理特殊字符
测试验证
- 测试所有支持的语言
- 验证格式化结果
- 检查资源完整性
性能优化
- 实现资源缓存
- 优化加载策略
- 减少运行时开销
通过合理的国际化和本地化策略,可以使应用更好地适应全球市场。在实际开发中,要注意平衡功能完整性和性能表现,确保良好的用户体验。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。