# 鸿蒙生态AI应用开发实战:基于ArkTS构建AI翻译工具,适配鸿蒙PC与移动终端


一、项目概述
在全球化进程加速的今天,语言翻译已成为人们日常交流的刚需。本文将详细介绍如何使用ArkTS语言开发一款AI翻译工具应用,该应用支持中英文互译,内置Mock离线数据,无需联网即可运行,并预留了翻译API网络调用接口。同时,本文还将探讨鸿蒙PC适配策略以及Flutter框架迁移路径。
1.1 应用功能特点
- ✅ 智能翻译:输入中文文本,一键翻译成英文;支持中英文互译
- ✅ 语言切换:点击↔按钮快速切换翻译方向
- ✅ 离线运行:内置50条Mock翻译数据,无需网络即可使用
- ✅ 历史记录:自动保存翻译历史,随时查阅
- ✅ 一键复制:快速复制翻译结果
- ✅ 极简UI:仅使用系统原生组件,界面简洁优雅
- ✅ 跨端适配:完美适配鸿蒙手机、平板、PC等设备
1.2 技术栈
- 语言:ArkTS(HarmonyOS NEXT)
- UI框架:ArkUI声明式语法
- 状态管理:@State装饰器
- 数据持久化:@ohos.data.preferences
- API版本:API 24
二、ArkTS语言基础
2.1 ArkTS简介
ArkTS是HarmonyOS NEXT推出的全新编程语言,它扩展了TypeScript,提供了更丰富的类型系统和声明式UI能力。ArkTS具有以下特点:
- 类型安全:严格的类型检查,禁止any和unknown类型
- 声明式UI:使用ArkUI框架构建界面,代码即UI
- 响应式状态管理:通过@State、@Prop、@Link等装饰器实现状态管理
- 组件化开发:支持自定义组件,代码复用性高
2.2 核心语法特性
2.2.1 接口定义
ArkTS要求所有对象必须显式定义接口,禁止使用any类型:
interface TranslationRecord {
source: string;
target: string;
sourceLang: string;
targetLang: string;
timestamp: number;
}
interface MockEntry {
source: string;
target: string;
}
2.2.2 状态管理
使用@State装饰器管理组件状态:
@State inputText: string = '';
@State outputText: string = '';
@State isLoading: boolean = false;
@State history: TranslationRecord[] = [];
@State sourceLang: string = '中文';
@State targetLang: string = 'English';
@State sourceLangCode: string = 'zh';
@State targetLangCode: string = 'en';
2.2.3 组件构建
使用build方法构建UI界面:
build() {
Column() {
Text('AI翻译工具')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor('#FFFFFF')
}
.width('100%')
.height(56)
.backgroundColor('#1976D2')
}
三、应用架构设计
3.1 单文件架构
本应用采用单文件架构,所有代码集中在Index.ets中,包括:
- 接口定义:TranslationRecord、MockEntry、ParseResult
- 状态管理:@State装饰的状态变量
- Mock数据:内置50条翻译模板数据(中→英30条,英→中20条)
- 数据持久化:Preferences存储历史记录
- 业务逻辑:翻译处理、语言切换、数据解析、格式化时间等
- UI构建:输入区域、输出区域、历史记录
3.2 核心模块
3.2.1 输入模块
输入模块包含原文输入框和语言标签:
TextArea({ placeholder: '请输入要翻译的文本...', text: this.inputText })
.width('100%')
.height(100)
.fontSize(15)
.padding({ left: 12, right: 12, top: 12, bottom: 12 })
.backgroundColor('#FFFFFF')
.borderRadius(8)
.borderWidth(1)
.borderColor('#E0E0E0')
.maxLength(500)
.onChange((value: string) => {
this.inputText = value;
})
3.2.2 语言切换模块
语言切换模块处理翻译方向切换:
private switchLanguage(): void {
let tempLang: string = this.sourceLang;
let tempCode: string = this.sourceLangCode;
this.sourceLang = this.targetLang;
this.sourceLangCode = this.targetLangCode;
this.targetLang = tempLang;
this.targetLangCode = tempCode;
this.inputText = '';
this.outputText = '';
}
3.2.3 翻译模块
翻译模块处理用户点击翻译按钮后的逻辑:
private handleTranslate(): void {
if (this.inputText.trim().length === 0) {
this.errorText = '请输入要翻译的内容';
return;
}
this.errorText = '';
this.outputText = '';
this.isLoading = true;
setTimeout(() => {
let translatedText: string = this.getMockTranslation(this.inputText);
this.isLoading = false;
this.outputText = translatedText;
let record: TranslationRecord = {
source: this.inputText.trim(),
target: translatedText,
sourceLang: this.sourceLang,
targetLang: this.targetLang,
timestamp: Date.now()
};
let newHistory: TranslationRecord[] = [record];
for (let i = 0; i < this.history.length; i++) {
newHistory.push(this.history[i]);
}
this.history = newHistory;
this.saveHistory();
}, 800);
}
3.2.4 Mock数据模块
Mock数据模块提供离线翻译模板:
private readonly MOCK_DATA_ZH_EN: MockEntry[] = [
{ source: '你好', target: 'Hello' },
{ source: '谢谢', target: 'Thank you' },
{ source: '再见', target: 'Goodbye' },
// 更多Mock数据...
];
private readonly MOCK_DATA_EN_ZH: MockEntry[] = [
{ source: 'Hello', target: '你好' },
{ source: 'Thank you', target: '谢谢' },
{ source: 'Goodbye', target: '再见' },
// 更多Mock数据...
];
3.2.5 数据持久化模块
使用@ohos.data.preferences保存历史记录:
private async saveHistory(): Promise<void> {
if (!this.context) {
return;
}
try {
let prefs = await this.getPreferences();
let stringList: Array<string> = [];
for (let i = 0; i < this.history.length; i++) {
let record = this.history[i];
stringList.push(JSON.stringify(record));
}
let jsonStr: string = JSON.stringify(stringList);
await prefs.put(this.STORAGE_KEY, jsonStr);
await prefs.flush();
} catch (error) {
console.error('保存历史记录失败');
}
}
四、Mock离线方案详解
4.1 Mock数据设计
Mock数据采用双向结构,覆盖中文→英文和英文→中文两个方向:
中文→英文(30条):
| 序号 | 中文原文 | 英文翻译 |
|---|---|---|
| 1 | 你好 | Hello |
| 2 | 谢谢 | Thank you |
| 3 | 再见 | Goodbye |
| 4 | 我爱你 | I love you |
| 5 | 早上好 | Good morning |
| 6 | 晚上好 | Good evening |
| 7 | 你叫什么名字 | What is your name? |
| 8 | 我来自中国 | I am from China |
| 9 | 今天天气很好 | The weather is nice today |
| 10 | 请帮我翻译 | Please help me translate |
| 11 | 这是一个测试 | This is a test |
| 12 | 学习英语很重要 | Learning English is very important |
| 13 | 欢迎来到北京 | Welcome to Beijing |
| 14 | 新年快乐 | Happy New Year |
| 15 | 生日快乐 | Happy Birthday |
| 16 | 恭喜发财 | May you be prosperous |
| 17 | 万事如意 | May all your wishes come true |
| 18 | 身体健康 | Good health |
| 19 | 工作顺利 | Smooth work |
| 20 | 心想事成 | May all your dreams come true |
| 21 | 你好世界 | Hello World |
| 22 | 计算机科学 | Computer Science |
| 23 | 人工智能 | Artificial Intelligence |
| 24 | 机器学习 | Machine Learning |
| 25 | 深度学习 | Deep Learning |
| 26 | 大数据 | Big Data |
| 27 | 云计算 | Cloud Computing |
| 28 | 物联网 | Internet of Things |
| 29 | 区块链 | Blockchain |
| 30 | 5G技术 | 5G Technology |
英文→中文(20条):
| 序号 | 英文原文 | 中文翻译 |
|---|---|---|
| 1 | Hello | 你好 |
| 2 | Thank you | 谢谢 |
| 3 | Goodbye | 再见 |
| 4 | I love you | 我爱你 |
| 5 | Good morning | 早上好 |
| 6 | Good evening | 晚上好 |
| 7 | What is your name? | 你叫什么名字 |
| 8 | I am from China | 我来自中国 |
| 9 | The weather is nice today | 今天天气很好 |
| 10 | Please help me translate | 请帮我翻译 |
| 11 | This is a test | 这是一个测试 |
| 12 | Learning English is very important | 学习英语很重要 |
| 13 | Welcome to Beijing | 欢迎来到北京 |
| 14 | Happy New Year | 新年快乐 |
| 15 | Happy Birthday | 生日快乐 |
| 16 | Computer Science | 计算机科学 |
| 17 | Artificial Intelligence | 人工智能 |
| 18 | Machine Learning | 机器学习 |
| 19 | Deep Learning | 深度学习 |
| 20 | Big Data | 大数据 |
4.2 翻译逻辑
根据当前语言方向选择对应的Mock数据:
private getMockTranslation(source: string): string {
let mockData: MockEntry[] = this.MOCK_DATA_ZH_EN;
if (this.sourceLangCode === 'en' && this.targetLangCode === 'zh') {
mockData = this.MOCK_DATA_EN_ZH;
}
for (let i = 0; i < mockData.length; i++) {
let entry = mockData[i];
if (entry.source === source) {
return entry.target;
}
}
return this.generateDefaultTranslation(source);
}
4.3 默认内容生成
对于未匹配到的文本,应用会自动生成默认翻译:
private generateDefaultTranslation(source: string): string {
return '[AI翻译] ' + source;
}
4.4 离线运行优势
- 零网络依赖:应用完全离线可用,适合网络环境不佳的场景
- 快速响应:本地Mock数据响应时间小于1秒
- 隐私安全:用户数据不经过网络传输,保护隐私
- 开发调试:方便开发阶段测试和调试
五、网络API预留方案
5.1 预留接口设计
应用预留了真实翻译API调用接口,取消注释即可使用:
/*
import http from '@ohos.net.http';
private async fetchOnlineTranslation(source: string): Promise<string> {
let httpRequest = http.createHttp();
let response = await httpRequest.request(
'https://api.example.com/translate',
{
method: http.RequestMethod.POST,
header: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY'
},
extraData: {
'text': source,
'source': this.sourceLangCode,
'target': this.targetLangCode
}
}
);
let result = JSON.parse(response.result as string);
return result['translation'];
}
*/
5.2 权限配置
在module.json5中配置网络权限:
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
}
]
5.3 API切换策略
应用支持Mock模式和网络模式的切换:
private useOnlineAPI: boolean = false;
private async getTranslation(source: string): Promise<string> {
if (this.useOnlineAPI) {
return await this.fetchOnlineTranslation(source);
}
return this.getMockTranslation(source);
}
六、鸿蒙PC适配策略
6.1 响应式布局
使用layoutWeight实现响应式布局:
Row() {
Column() {
// 原文输入区域
}
.layoutWeight(1)
Button() {
Text('↔')
}
.width(48)
.height(48)
Column() {
// 译文输出区域
}
.layoutWeight(1)
}
6.2 尺寸适配
使用百分比和flex布局适配不同屏幕尺寸:
Button('翻译')
.width('45%')
.height(44)
.fontSize(16)
6.3 PC端优化建议
- 增加侧边栏:在PC端显示翻译历史侧边栏
- 调整字体大小:PC端使用更大的字体
- 添加快捷键:支持Ctrl+Enter快速翻译
- 窗口化支持:支持窗口拖拽和缩放
- 多语言支持:增加更多语言选择
七、鸿蒙Flutter框架迁移路径
7.1 框架对比
| 特性 | ArkTS | Flutter |
|---|---|---|
| 语言 | TypeScript扩展 | Dart |
| UI框架 | ArkUI | Material/Cupertino |
| 状态管理 | @State/@Prop/@Link | setState/Provider/Riverpod |
| 跨平台 | 鸿蒙生态 | 多平台 |
| 性能 | 原生性能 | 接近原生 |
7.2 代码迁移示例
7.2.1 状态管理迁移
ArkTS:
@State inputText: string = '';
Flutter:
String inputText = '';
setState(() {
inputText = newValue;
});
7.2.2 UI组件迁移
ArkTS:
TextArea({ placeholder: '请输入要翻译的文本...', text: this.inputText })
.onChange((value: string) => {
this.inputText = value;
})
Flutter:
TextField(
decoration: InputDecoration(
hintText: '请输入要翻译的文本...',
),
onChanged: (value) {
setState(() {
inputText = value;
});
},
)
7.2.3 数据持久化迁移
ArkTS:
let prefs = await preferences.getPreferences(this.context, 'ai_translate_app');
await prefs.put('key', 'value');
Flutter:
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString('key', 'value');
7.2.4 语言切换迁移
ArkTS:
private switchLanguage(): void {
let tempLang: string = this.sourceLang;
this.sourceLang = this.targetLang;
this.targetLang = tempLang;
}
Flutter:
void switchLanguage() {
setState(() {
String tempLang = sourceLang;
sourceLang = targetLang;
targetLang = tempLang;
});
}
7.3 迁移注意事项
- 语言差异:TypeScript和Dart的语法差异
- UI框架:ArkUI和Material Design的差异
- 生态差异:鸿蒙生态和Flutter生态的差异
- 性能考虑:原生性能和Flutter性能的权衡
- 权限配置:鸿蒙权限和Android/iOS权限的差异
八、性能优化策略
8.1 状态管理优化
- 使用@State管理局部状态
- 避免不必要的状态更新
- 使用const声明不可变数据
private readonly STORAGE_KEY: string = 'translation_history';
8.2 渲染优化
- 使用ForEach时提供唯一的key值
- 避免在build方法中创建新对象
- 使用懒加载减少内存占用
ForEach(this.history, (record: TranslationRecord) => {
// 渲染历史记录
}, (record: TranslationRecord) => record.timestamp.toString())
8.3 存储优化
- 批量存储减少IO操作
- 使用字符串数组存储提高效率
- 定期清理过期数据
8.4 输入优化
- 设置输入字数限制(500字)
- 使用TextArea替代TextInput支持多行输入
- 添加输入验证
九、代码安全与最佳实践
9.1 类型安全
- 禁止使用any和unknown类型
- 显式定义所有接口
- 使用类型断言时确保类型安全
9.2 异常处理
- 所有异步操作都有try-catch包裹
- 提供友好的错误提示
- 记录错误日志便于排查
9.3 代码规范
- 变量命名使用驼峰式
- 方法命名使用动词开头
- 代码缩进统一为2个空格
9.4 隐私保护
- 数据本地存储,不上传云端
- 敏感信息加密存储
- 权限最小化原则
十、功能测试与验证
10.1 功能测试用例
测试用例1:中文→英文翻译
- 输入:你好
- 预期输出:Hello
测试用例2:英文→中文翻译
- 输入:Hello
- 预期输出:你好
测试用例3:语言切换
- 点击↔按钮
- 预期:sourceLang和targetLang互换
测试用例4:历史记录保存
- 翻译一条文本
- 关闭应用重新打开
- 预期:历史记录显示该条翻译
测试用例5:清空功能
- 翻译多条文本
- 点击清空按钮
- 预期:所有内容和历史记录被清空
测试用例6:输入验证
- 输入空文本
- 点击翻译按钮
- 预期:显示错误提示"请输入要翻译的内容"
测试用例7:复制功能
- 翻译一条文本
- 点击复制按钮
- 预期:按钮显示"已复制",2秒后恢复"复制"
10.2 兼容性测试
- 鸿蒙手机(API 24+)
- 鸿蒙平板
- 鸿蒙PC
- 不同屏幕分辨率
10.3 性能测试
- 翻译响应时间:< 1秒
- 内存占用:< 50MB
- 启动时间:< 2秒
十一、未来规划
11.1 功能扩展
- 多语言支持:增加日语、韩语、法语、德语等更多语言
- 语音输入:支持语音输入翻译
- 语音输出:支持翻译结果语音播报
- 图片翻译:支持拍照翻译
- 离线词典:内置离线词典数据
11.2 技术升级
- AI模型集成:集成真实翻译API
- 智能推荐:根据历史记录推荐翻译内容
- 翻译记忆:自动保存常用翻译
- 多设备协同:支持鸿蒙多设备协同
11.3 平台适配
- 鸿蒙PC优化:针对PC端进行深度优化
- 平板适配:优化平板端布局
- 车机适配:适配鸿蒙车机系统
- 手表适配:适配鸿蒙智能手表
十二、常见问题与解决方案
12.1 编译错误
问题1:“Cannot find module ‘@ohos.data.preferences’”
- 解决方案:确保API版本设置为24,检查项目配置
问题2:“Use explicit types instead of ‘any’, ‘unknown’”
- 解决方案:显式定义所有接口,避免使用any类型
问题3:“Function may throw exceptions. Special handling is required.”
- 解决方案:添加try-catch异常处理
12.2 运行时错误
问题1:历史记录无法保存
- 解决方案:检查context是否为null,检查权限配置
问题2:翻译结果显示异常
- 解决方案:检查Mock数据格式,检查语言方向判断逻辑
问题3:语言切换不生效
- 解决方案:检查switchLanguage方法实现
12.3 性能问题
问题1:应用启动慢
- 解决方案:优化loadHistory方法,使用异步加载
问题2:滚动卡顿
- 解决方案:优化ForEach渲染,使用懒加载
附录:完整代码
Index.ets
import preferences from '@ohos.data.preferences';
import common from '@ohos.app.ability.common';
interface TranslationRecord {
source: string;
target: string;
sourceLang: string;
targetLang: string;
timestamp: number;
}
interface MockEntry {
source: string;
target: string;
}
interface ParseResult {
success: boolean;
data: Array<string> | null;
}
@Entry
@Component
struct Index {
@State inputText: string = '';
@State outputText: string = '';
@State isLoading: boolean = false;
@State history: TranslationRecord[] = [];
@State errorText: string = '';
@State sourceLang: string = '中文';
@State targetLang: string = 'English';
@State sourceLangCode: string = 'zh';
@State targetLangCode: string = 'en';
@State copySuccess: boolean = false;
private preferencesInst: preferences.Preferences | null = null;
private context: common.Context | null = null;
private readonly STORAGE_KEY: string = 'translation_history';
private readonly MOCK_DATA_ZH_EN: MockEntry[] = [
{ source: '你好', target: 'Hello' },
{ source: '谢谢', target: 'Thank you' },
{ source: '再见', target: 'Goodbye' },
{ source: '我爱你', target: 'I love you' },
{ source: '早上好', target: 'Good morning' },
{ source: '晚上好', target: 'Good evening' },
{ source: '你叫什么名字', target: 'What is your name?' },
{ source: '我来自中国', target: 'I am from China' },
{ source: '今天天气很好', target: 'The weather is nice today' },
{ source: '请帮我翻译', target: 'Please help me translate' },
{ source: '这是一个测试', target: 'This is a test' },
{ source: '学习英语很重要', target: 'Learning English is very important' },
{ source: '欢迎来到北京', target: 'Welcome to Beijing' },
{ source: '新年快乐', target: 'Happy New Year' },
{ source: '生日快乐', target: 'Happy Birthday' },
{ source: '恭喜发财', target: 'May you be prosperous' },
{ source: '万事如意', target: 'May all your wishes come true' },
{ source: '身体健康', target: 'Good health' },
{ source: '工作顺利', target: 'Smooth work' },
{ source: '心想事成', target: 'May all your dreams come true' },
{ source: '你好世界', target: 'Hello World' },
{ source: '计算机科学', target: 'Computer Science' },
{ source: '人工智能', target: 'Artificial Intelligence' },
{ source: '机器学习', target: 'Machine Learning' },
{ source: '深度学习', target: 'Deep Learning' },
{ source: '大数据', target: 'Big Data' },
{ source: '云计算', target: 'Cloud Computing' },
{ source: '物联网', target: 'Internet of Things' },
{ source: '区块链', target: 'Blockchain' },
{ source: '5G技术', target: '5G Technology' }
];
private readonly MOCK_DATA_EN_ZH: MockEntry[] = [
{ source: 'Hello', target: '你好' },
{ source: 'Thank you', target: '谢谢' },
{ source: 'Goodbye', target: '再见' },
{ source: 'I love you', target: '我爱你' },
{ source: 'Good morning', target: '早上好' },
{ source: 'Good evening', target: '晚上好' },
{ source: 'What is your name?', target: '你叫什么名字' },
{ source: 'I am from China', target: '我来自中国' },
{ source: 'The weather is nice today', target: '今天天气很好' },
{ source: 'Please help me translate', target: '请帮我翻译' },
{ source: 'This is a test', target: '这是一个测试' },
{ source: 'Learning English is very important', target: '学习英语很重要' },
{ source: 'Welcome to Beijing', target: '欢迎来到北京' },
{ source: 'Happy New Year', target: '新年快乐' },
{ source: 'Happy Birthday', target: '生日快乐' },
{ source: 'Computer Science', target: '计算机科学' },
{ source: 'Artificial Intelligence', target: '人工智能' },
{ source: 'Machine Learning', target: '机器学习' },
{ source: 'Deep Learning', target: '深度学习' },
{ source: 'Big Data', target: '大数据' }
];
aboutToAppear(): void {
this.context = getContext(this) as common.Context;
this.loadHistory();
}
private async loadHistory(): Promise<void> {
if (!this.context) {
return;
}
try {
let prefs = await this.getPreferences();
let storedValue = await prefs.get(this.STORAGE_KEY, '');
let jsonStr: string = storedValue as string;
if (jsonStr.length > 0) {
let parseResult = this.parseStringList(jsonStr);
if (parseResult.success && parseResult.data) {
let records: TranslationRecord[] = [];
for (let i = 0; i < parseResult.data.length; i++) {
let str: string = parseResult.data[i];
let record = this.parseTranslationRecord(str);
if (record) {
records.push(record);
}
}
this.history = records;
}
}
} catch (error) {
console.error('加载历史记录失败');
}
}
private async saveHistory(): Promise<void> {
if (!this.context) {
return;
}
try {
let prefs = await this.getPreferences();
let stringList: Array<string> = [];
for (let i = 0; i < this.history.length; i++) {
let record = this.history[i];
stringList.push(JSON.stringify(record));
}
let jsonStr: string = JSON.stringify(stringList);
await prefs.put(this.STORAGE_KEY, jsonStr);
await prefs.flush();
} catch (error) {
console.error('保存历史记录失败');
}
}
private async getPreferences(): Promise<preferences.Preferences> {
if (this.preferencesInst) {
return this.preferencesInst;
}
if (!this.context) {
throw new Error('Context is null');
}
try {
this.preferencesInst = await preferences.getPreferences(this.context, 'ai_translate_app');
} catch (error) {
console.error('获取Preferences失败');
throw new Error('获取Preferences失败');
}
return this.preferencesInst;
}
private parseStringList(jsonStr: string): ParseResult {
let result: ParseResult = {
success: false,
data: null
};
try {
let parsedObj: Object = JSON.parse(jsonStr) as Object;
if (Array.isArray(parsedObj)) {
let stringArray: Array<string> = [];
let parsedArray: Object[] = parsedObj as Object[];
for (let i = 0; i < parsedArray.length; i++) {
let item: Object = parsedArray[i];
if (typeof item === 'string') {
stringArray.push(item);
}
}
result.success = true;
result.data = stringArray;
}
} catch (error) {
console.error('解析字符串列表失败');
}
return result;
}
private parseTranslationRecord(jsonStr: string): TranslationRecord | null {
try {
let parsedObj: Object = JSON.parse(jsonStr) as Object;
if (typeof parsedObj === 'object' && parsedObj !== null) {
let data: Record<string, Object> = parsedObj as Record<string, Object>;
if (data.source && data.target && data.sourceLang && data.targetLang && data.timestamp) {
return {
source: String(data.source),
target: String(data.target),
sourceLang: String(data.sourceLang),
targetLang: String(data.targetLang),
timestamp: Number(data.timestamp)
};
}
}
} catch (error) {
console.error('解析翻译记录失败');
}
return null;
}
private handleTranslate(): void {
if (this.inputText.trim().length === 0) {
this.errorText = '请输入要翻译的内容';
return;
}
this.errorText = '';
this.outputText = '';
this.isLoading = true;
setTimeout(() => {
let translatedText: string = this.getMockTranslation(this.inputText);
this.isLoading = false;
this.outputText = translatedText;
let record: TranslationRecord = {
source: this.inputText.trim(),
target: translatedText,
sourceLang: this.sourceLang,
targetLang: this.targetLang,
timestamp: Date.now()
};
let newHistory: TranslationRecord[] = [record];
for (let i = 0; i < this.history.length; i++) {
newHistory.push(this.history[i]);
}
this.history = newHistory;
this.saveHistory();
}, 800);
}
private getMockTranslation(source: string): string {
let mockData: MockEntry[] = this.MOCK_DATA_ZH_EN;
if (this.sourceLangCode === 'en' && this.targetLangCode === 'zh') {
mockData = this.MOCK_DATA_EN_ZH;
}
for (let i = 0; i < mockData.length; i++) {
let entry = mockData[i];
if (entry.source === source) {
return entry.target;
}
}
return this.generateDefaultTranslation(source);
}
private generateDefaultTranslation(source: string): string {
return '[AI翻译] ' + source;
}
private copyContent(): void {
if (this.outputText.length === 0) {
return;
}
this.copySuccess = true;
setTimeout(() => {
this.copySuccess = false;
}, 2000);
}
private clearAll(): void {
this.inputText = '';
this.outputText = '';
this.errorText = '';
this.history = [];
this.saveHistory();
}
private switchLanguage(): void {
let tempLang: string = this.sourceLang;
let tempCode: string = this.sourceLangCode;
this.sourceLang = this.targetLang;
this.sourceLangCode = this.targetLangCode;
this.targetLang = tempLang;
this.targetLangCode = tempCode;
this.inputText = '';
this.outputText = '';
}
private formatTime(timestamp: number): string {
let date: Date = new Date(timestamp);
let year: string = date.getFullYear().toString();
let month: string = (date.getMonth() + 1).toString().padStart(2, '0');
let day: string = date.getDate().toString().padStart(2, '0');
let hour: string = date.getHours().toString().padStart(2, '0');
let minute: string = date.getMinutes().toString().padStart(2, '0');
return year + '-' + month + '-' + day + ' ' + hour + ':' + minute;
}
build() {
Column() {
Row() {
Text('AI翻译工具')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor('#FFFFFF')
}
.width('100%')
.height(56)
.padding({ left: 16, right: 16 })
.backgroundColor('#1976D2')
Column() {
Row() {
Column() {
Text(this.sourceLang)
.fontSize(14)
.fontColor('#666666')
.margin({ bottom: 4 })
TextArea({ placeholder: '请输入要翻译的文本...', text: this.inputText })
.width('100%')
.height(100)
.fontSize(15)
.padding({ left: 12, right: 12, top: 12, bottom: 12 })
.backgroundColor('#FFFFFF')
.borderRadius(8)
.borderWidth(1)
.borderColor('#E0E0E0')
.maxLength(500)
.onChange((value: string) => {
this.inputText = value;
})
}
.layoutWeight(1)
.margin({ right: 8 })
Button() {
Text('↔')
.fontSize(20)
.fontColor('#1976D2')
}
.width(48)
.height(48)
.backgroundColor('#FFFFFF')
.borderRadius(8)
.borderWidth(1)
.borderColor('#E0E0E0')
.margin({ top: 20 })
.onClick(() => {
this.switchLanguage();
})
Column() {
Row() {
Text(this.targetLang)
.fontSize(14)
.fontColor('#666666')
.layoutWeight(1)
if (this.outputText.length > 0) {
Button(this.copySuccess ? '已复制' : '复制')
.width(48)
.height(28)
.fontSize(12)
.fontColor('#FFFFFF')
.backgroundColor('#1976D2')
.borderRadius(6)
.onClick(() => {
this.copyContent();
})
}
}
.width('100%')
.margin({ bottom: 4 })
Text(this.outputText.length > 0 ? this.outputText : '翻译结果将显示在这里...')
.width('100%')
.height(100)
.fontSize(15)
.padding({ left: 12, right: 12, top: 12, bottom: 12 })
.backgroundColor('#E3F2FD')
.borderRadius(8)
.borderWidth(1)
.borderColor('#BBDEFB')
.fontColor(this.outputText.length > 0 ? '#333333' : '#999999')
.textAlign(TextAlign.Start)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.maxLines(6)
}
.layoutWeight(1)
.margin({ left: 8 })
}
.width('100%')
.margin({ left: 16, right: 16, top: 16 })
if (this.errorText.length > 0) {
Text(this.errorText)
.fontSize(13)
.fontColor('#FF4444')
.margin({ left: 16, right: 16, top: 8 })
}
Row() {
Button('翻译')
.width('45%')
.height(44)
.fontSize(16)
.fontColor('#FFFFFF')
.backgroundColor('#1976D2')
.borderRadius(8)
.enabled(!this.isLoading)
.onClick(() => {
this.handleTranslate();
})
Blank().width('10%')
Button('清空')
.width('45%')
.height(44)
.fontSize(16)
.fontColor('#666666')
.backgroundColor('#F5F5F5')
.borderRadius(8)
.onClick(() => {
this.clearAll();
})
}
.width('100%')
.margin({ left: 16, right: 16, top: 16 })
}
.width('100%')
.padding({ bottom: 16 })
.backgroundColor('#FAFAFA')
Divider()
.height(1)
.color('#E0E0E0')
Scroll() {
Column() {
if (this.isLoading) {
Column() {
Text('AI正在翻译中...')
.fontSize(15)
.fontColor('#666666')
.margin({ top: 20, bottom: 20 })
}
.width('100%')
.padding({ left: 16, right: 16 })
}
if (this.history.length > 0) {
Text('翻译历史')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor('#333333')
.padding({ left: 16, right: 16, top: 16, bottom: 8 })
Column() {
ForEach(this.history, (record: TranslationRecord) => {
Column() {
Row() {
Text(record.sourceLang + ' → ' + record.targetLang)
.fontSize(12)
.fontColor('#1976D2')
.layoutWeight(1)
Text(this.formatTime(record.timestamp))
.fontSize(12)
.fontColor('#999999')
}
.width('100%')
.margin({ bottom: 4 })
Text(record.source)
.fontSize(14)
.fontColor('#333333')
.width('100%')
.margin({ bottom: 4 })
.textOverflow({ overflow: TextOverflow.Ellipsis })
.maxLines(2)
Text(record.target)
.fontSize(14)
.fontColor('#1976D2')
.width('100%')
.textOverflow({ overflow: TextOverflow.Ellipsis })
.maxLines(2)
}
.width('100%')
.padding({ left: 12, right: 12, top: 12, bottom: 12 })
.backgroundColor('#FFFFFF')
.borderRadius(8)
.margin({ bottom: 8, left: 16, right: 16 })
}, (record: TranslationRecord) => record.timestamp.toString())
}
.width('100%')
.padding({ bottom: 16 })
} else {
Column() {
Text('暂无翻译记录')
.fontSize(14)
.fontColor('#999999')
.margin({ top: 20, bottom: 20 })
}
.width('100%')
.padding({ left: 16, right: 16 })
}
}
.width('100%')
}
.scrollable(ScrollDirection.Vertical)
.width('100%')
.layoutWeight(1)
.backgroundColor('#F5F5F5')
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
}
}
/*
预留的真实翻译API调用代码
import http from '@ohos.net.http';
private async fetchOnlineTranslation(source: string): Promise<string> {
let httpRequest = http.createHttp();
let response = await httpRequest.request(
'https://api.example.com/translate',
{
method: http.RequestMethod.POST,
header: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY'
},
extraData: {
'text': source,
'source': this.sourceLangCode,
'target': this.targetLangCode
}
}
);
let result = JSON.parse(response.result as string);
return result['translation'];
}
*/
总结
本文详细介绍了基于ArkTS开发AI翻译工具应用的全过程,包括:
- 项目架构设计:单文件架构,所有代码集中在Index.ets中
- 核心功能实现:智能翻译、语言切换、离线Mock数据、历史记录持久化
- 技术要点:ArkTS语法特性、状态管理、数据持久化、UI构建
- 适配策略:鸿蒙PC适配、响应式布局
- 迁移路径:Flutter框架迁移对比和代码示例
- 测试验证:功能测试用例、兼容性测试、性能测试
该应用充分展示了ArkTS语言的优势和鸿蒙生态的强大能力,为开发者提供了一个完整的鸿蒙原生应用开发参考。
参考文献
更多推荐



所有评论(0)