Cordova 开发鸿蒙PC应用翻译应用实现技术博客
目录
项目概述
翻译应用是一个基于 Cordova 框架开发的移动应用,通过调用第三方 API 实现多语言文本翻译功能。用户只需输入文本,选择源语言和目标语言,即可快速获得准确的翻译结果。应用支持自动语言检测和 30+ 种语言的互译。
预览

核心功能
- ✅ 多语言支持:支持 30+ 种语言的翻译
- ✅ 自动语言检测:系统能够自动识别输入文本的语言
- ✅ 灵活的语言选择:支持手动指定源语言和目标语言
- ✅ Token 管理:自动保存和加载 API Token
- ✅ 响应式设计:完美适配移动设备和桌面浏览器
- ✅ 用户友好界面:美观的 UI 设计和流畅的交互体验
技术选型
前端技术栈
- HTML5:页面结构
- CSS3:样式设计和响应式布局
- JavaScript (ES6+):业务逻辑和 API 调用
- Cordova:跨平台移动应用框架
API 服务
- API 提供商 :AlAPI(alapi.cn)
- API 端点 :
https://v3.alapi.cn/api/fanyi - 请求方式:POST
- 数据格式:URL-encoded form data
功能需求分析
1. 用户输入需求
- API Token(必填)
- 要翻译的文本(必填)
- 源语言(可选,默认自动检测)
- 目标语言(可选,默认英语)
2. 功能需求
- 表单验证
- API 调用和错误处理
- 翻译结果展示(原文、译文、语言信息)
- Token 本地存储
- 加载状态提示
- 错误信息提示
3. 用户体验需求
- 响应式设计
- 流畅的交互动画
- 清晰的错误提示
- Token 获取引导
- 多语言名称显示
实现步骤
步骤 1: 创建页面结构
创建 translate.html 文件,包含:
- 导航栏
- 页面标题和说明
- 表单区域(Token、文本输入、语言选择)
- 结果展示区域
- Token 获取弹窗
步骤 2: 设计 UI 样式
使用 CSS3 实现:
- 响应式布局
- 渐变背景和阴影效果
- 表单样式和焦点效果
- 弹窗样式
- 移动端适配
步骤 3: 实现 JavaScript 逻辑
创建 translate.js 文件,实现:
- 表单提交处理
- API 调用
- 数据验证
- 结果展示
- Token 存储
- 语言名称映射
步骤 4: 配置安全策略
更新 Content Security Policy (CSP),允许:
- 访问 API 域名
- 加载 iframe 内容
- 执行必要的脚本
核心代码解析
1. HTML 结构
表单部分
html
<form id="translate-form">
<div class="form-group">
<label for="token" class="label-with-help">
<span>API Token *</span>
<button type="button" class="help-btn" onclick="openTokenModal()">获取 Token</button>
</label>
<div class="token-input-wrapper">
<input type="text" id="token" name="token" placeholder="请输入API Token" required>
</div>
</div>
<div class="form-group">
<label for="text">要翻译的文本 *</label>
<textarea id="text" name="text" placeholder="请输入要翻译的文本" required></textarea>
</div>
<div class="form-row">
<div class="form-group">
<label for="from">源语言</label>
<select id="from" name="from">
<option value="auto">自动检测</option>
<option value="zh" selected>中文</option>
<option value="en">英语</option>
<!-- 更多语言选项... -->
</select>
</div>
<div class="form-group">
<label for="to">目标语言</label>
<select id="to" name="to">
<option value="zh">中文</option>
<option value="en" selected>英语</option>
<!-- 更多语言选项... -->
</select>
</div>
</div>
<button type="submit" class="submit-btn" id="submit-btn">翻译</button>
</form>
结果展示区域
html
<div class="result-container" id="result-container">
<div class="result-title">翻译结果</div>
<div class="translate-result">
<div class="translate-item">
<div class="translate-label">原文</div>
<div class="translate-text source" id="source-text"></div>
</div>
<div class="translate-item">
<div class="translate-label">译文</div>
<div class="translate-text target" id="target-text"></div>
</div>
<div class="language-info">
<span>源语言:<strong id="from-lang"></strong></span>
<span>目标语言:<strong id="to-lang"></strong></span>
</div>
</div>
</div>
2. CSS 样式设计
响应式表单布局
css
.form-container {
background-color: #f8f9fa;
padding: 25px;
border-radius: 8px;
margin-bottom: 30px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.form-group textarea {
min-height: 120px;
resize: vertical;
font-family: inherit;
}
.form-group input:focus,
.form-group textarea:focus,
.form-group select:focus {
outline: none;
border-color: #3498db;
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
}
翻译结果样式
css
.translate-result {
background-color: white;
padding: 25px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.translate-item {
margin-bottom: 20px;
padding-bottom: 20px;
border-bottom: 1px solid #eee;
}
.translate-label {
font-size: 12px;
color: #7f8c8d;
margin-bottom: 8px;
text-transform: uppercase;
font-weight: bold;
}
.translate-text {
font-size: 18px;
line-height: 1.8;
color: #2c3e50;
word-wrap: break-word;
}
.translate-text.source {
color: #555;
}
.translate-text.target {
color: #2980b9;
font-weight: 500;
}
3. JavaScript 核心逻辑
语言名称映射
javascript
// 语言名称映射
const languageNames = {
'auto': '自动检测',
'zh': '中文',
'en': '英语',
'yue': '粤语',
'wyw': '文言文',
'jp': '日语',
'kor': '韩语',
'fra': '法语',
'spa': '西班牙语',
'th': '泰语',
'ara': '阿拉伯语',
'ru': '俄语',
'pt': '葡萄牙语',
'de': '德语',
'it': '意大利语',
'el': '希腊语',
'nl': '荷兰语',
'pl': '波兰语',
'bul': '保加利亚语',
'est': '爱沙尼亚语',
'dan': '丹麦语',
'fin': '芬兰语',
'cs': '捷克语',
'rom': '罗马尼亚语',
'slo': '斯洛文尼亚语',
'swe': '瑞典语',
'hu': '匈牙利语',
'cht': '繁体中文',
'vie': '越南语'
};
API 调用函数
javascript
function translateText() {
const submitBtn = document.getElementById('submit-btn');
const loading = document.getElementById('loading');
const errorMessage = document.getElementById('error-message');
const resultContainer = document.getElementById('result-container');
// 获取表单数据
const formData = {
token: document.getElementById('token').value.trim(),
q: document.getElementById('text').value.trim(),
from: document.getElementById('from').value,
to: document.getElementById('to').value
};
// 验证文本
if (!formData.q) {
showError('请输入要翻译的文本');
return;
}
// 验证token
if (!formData.token) {
showError('请输入API Token');
return;
}
// 显示加载状态
submitBtn.disabled = true;
submitBtn.textContent = '翻译中...';
loading.classList.add('show');
errorMessage.classList.remove('show');
resultContainer.classList.remove('show');
// 构建请求参数
const params = new URLSearchParams();
params.append('token', formData.token);
params.append('q', formData.q);
params.append('from', formData.from);
params.append('to', formData.to);
// 发送POST请求
fetch('https://v3.alapi.cn/api/fanyi', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: params.toString()
})
.then(response => {
if (!response.ok) {
throw new Error('网络请求失败: ' + response.status);
}
return response.json();
})
.then(data => {
console.log('API响应:', data);
if (data.success && data.code === 200) {
displayTranslation(data.data);
} else {
showError(data.message || '翻译失败,请检查参数');
}
})
.catch(error => {
console.error('请求错误:', error);
showError('请求失败: ' + error.message + '。请检查网络连接或API Token是否正确');
})
.finally(() => {
// 恢复按钮状态
submitBtn.disabled = false;
submitBtn.textContent = '翻译';
loading.classList.remove('show');
});
}
结果展示函数
javascript
function displayTranslation(data) {
const resultContainer = document.getElementById('result-container');
const sourceText = document.getElementById('source-text');
const targetText = document.getElementById('target-text');
const fromLang = document.getElementById('from-lang');
const toLang = document.getElementById('to-lang');
// 显示原文
if (data.src) {
sourceText.textContent = data.src;
} else {
sourceText.textContent = '无原文';
}
// 显示译文
if (data.dst) {
targetText.textContent = data.dst;
} else {
targetText.textContent = '无译文';
}
// 显示语言信息
if (data.from) {
fromLang.textContent = languageNames[data.from] || data.from;
} else {
fromLang.textContent = '未知';
}
if (data.to) {
toLang.textContent = languageNames[data.to] || data.to;
} else {
toLang.textContent = '未知';
}
// 显示结果容器
resultContainer.classList.add('show');
// 滚动到结果区域
resultContainer.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
Token 本地存储
javascript
// 页面加载完成后的初始化
document.addEventListener('DOMContentLoaded', function() {
// 尝试从本地存储加载token
const savedToken = localStorage.getItem('translate_api_token');
if (savedToken) {
document.getElementById('token').value = savedToken;
}
// 保存token到本地存储
document.getElementById('token').addEventListener('blur', function() {
const token = this.value.trim();
if (token) {
localStorage.setItem('translate_api_token', token);
}
});
console.log('翻译页面加载完成');
});
API 集成详解
API 请求参数
| 参数名 | 类型 | 必填 | 说明 | 示例 |
|---|---|---|---|---|
| token | string | 是 | 接口调用token,需要在token管理中创建 | qlVquQZPYSeaCi6u |
| q | string | 是 | 要翻译的文本 | 你好啊 |
| from | string | 否 | 来源语种。默认 zh | zh、auto |
| to | string | 否 | 翻译语种,默认en | en |
API 响应格式
json
{
"request_id": "850395543089061888",
"success": true,
"message": "success",
"code": 200,
"data": {
"from": "zh",
"to": "en",
"src": "鸿蒙生态",
"dst": "HarmonyOS ecology"
},
"time": 1763710097,
"usage": 0
}
请求实现
javascript
// 构建请求参数
const params = new URLSearchParams();
params.append('token', formData.token);
params.append('q', formData.q);
params.append('from', formData.from);
params.append('to', formData.to);
// 发送POST请求
fetch('https://v3.alapi.cn/api/fanyi', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: params.toString()
})
错误处理
javascript
.then(response => {
if (!response.ok) {
throw new Error('网络请求失败: ' + response.status);
}
return response.json();
})
.then(data => {
if (data.success && data.code === 200) {
displayTranslation(data.data);
} else {
showError(data.message || '翻译失败,请检查参数');
}
})
.catch(error => {
console.error('请求错误:', error);
showError('请求失败: ' + error.message + '。请检查网络连接或API Token是否正确');
});
用户体验优化
1. 表单验证
前端验证
javascript
// 验证文本
if (!formData.q) {
showError('请输入要翻译的文本');
return;
}
// 验证token
if (!formData.token) {
showError('请输入API Token');
return;
}
HTML5 验证
html
<textarea id="text" name="text" placeholder="请输入要翻译的文本" required></textarea>
<input type="text" id="token" name="token" placeholder="请输入API Token" required>
2. 加载状态提示
javascript
// 显示加载状态
submitBtn.disabled = true;
submitBtn.textContent = '翻译中...';
loading.classList.add('show');
// 恢复按钮状态
submitBtn.disabled = false;
submitBtn.textContent = '翻译';
loading.classList.remove('show');
3. 语言名称友好显示
javascript
// 使用语言名称映射,将语言代码转换为友好的中文名称
if (data.from) {
fromLang.textContent = languageNames[data.from] || data.from;
} else {
fromLang.textContent = '未知';
}
4. 结果展示优化
css
.translate-text {
font-size: 18px;
line-height: 1.8;
color: #2c3e50;
word-wrap: break-word; /* 长文本自动换行 */
}
.translate-text.source {
color: #555; /* 原文使用较淡的颜色 */
}
.translate-text.target {
color: #2980b9; /* 译文使用醒目的蓝色 */
font-weight: 500;
}
5. 自动滚动到结果
javascript
// 滚动到结果区域
resultContainer.scrollIntoView({ behavior: 'smooth', block: 'start' });
常见问题与解决方案
问题 1: 跨域请求失败
原因:浏览器的同源策略限制
解决方案:
- 配置正确的 CSP 策略
- 使用
fetchAPI(Cordova 环境支持跨域) - 确保 API 服务器支持 CORS
html
<meta http-equiv="Content-Security-Policy"
content="default-src 'self' data: https://ssl.gstatic.com https://v3.alapi.cn https://www.alapi.cn 'unsafe-eval';
style-src 'self' 'unsafe-inline';
media-src *;
img-src 'self' data: content:;
script-src 'self' 'unsafe-inline' 'unsafe-eval';
connect-src 'self' https://v3.alapi.cn https://www.alapi.cn;
frame-src https://www.alapi.cn;">
问题 2: 长文本显示问题
原因:文本过长导致布局混乱
解决方案:
css
.translate-text {
word-wrap: break-word; /* 自动换行 */
word-break: break-all; /* 允许在任意字符间换行 */
overflow-wrap: break-word; /* 兼容性更好的换行 */
}
问题 3: 自动检测语言不准确
原因:API 自动检测可能误判
解决方案:
- 提供手动选择源语言的选项
- 默认使用自动检测,但允许用户覆盖
- 在结果中显示检测到的语言,让用户确认
javascript
// 如果自动检测结果不准确,用户可以手动选择源语言
<select id="from" name="from">
<option value="auto">自动检测</option>
<option value="zh" selected>中文</option>
<!-- 其他语言选项 -->
</select>
问题 4: Token 丢失
原因:浏览器清除缓存或 localStorage 被清空
解决方案:
- 使用
localStorage持久化存储 - 添加 Token 输入提示
- 提供快速获取 Token 的入口
问题 5: 移动端输入体验不佳
原因:textarea 在移动端可能显示异常
解决方案:
css
.form-group textarea {
min-height: 120px;
resize: vertical; /* 允许垂直调整大小 */
font-family: inherit; /* 继承字体 */
font-size: 16px; /* 防止 iOS 自动缩放 */
}
最佳实践
1. 代码组织
- 分离关注点:HTML 负责结构,CSS 负责样式,JavaScript 负责逻辑
- 模块化设计:将功能拆分为独立的函数
- 命名规范:使用有意义的变量和函数名
2. 错误处理
javascript
// 完善的错误处理链
fetch(url, options)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(data => {
if (data.success) {
// 处理成功情况
} else {
throw new Error(data.message || '未知错误');
}
})
.catch(error => {
// 统一错误处理
console.error('Error:', error);
showError(error.message);
});
3. 用户体验
- 即时反馈:按钮状态、加载提示、错误信息
- 数据持久化:Token 自动保存
- 无障碍访问:合理的标签和提示文字
- 响应式设计:适配各种屏幕尺寸
4. 性能优化
javascript
// 防抖处理(避免频繁请求)
let debounceTimer;
function translateTextDebounced() {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
translateText();
}, 500);
}
// 请求取消(避免重复请求)
let currentController = null;
function translateText() {
// 取消之前的请求
if (currentController) {
currentController.abort();
}
currentController = new AbortController();
fetch(url, {
signal: currentController.signal,
// ...
});
}
5. 安全性
- 输入验证:前端和后端双重验证
- CSP 配置:限制资源加载来源
- Token 安全:不在代码中硬编码 Token
- HTTPS:生产环境使用 HTTPS
- XSS 防护 :使用
textContent而非innerHTML
项目结构
www/
├── translate.html # 翻译页面
├── js/
│ └── translate.js # 翻译功能脚本
├── index.html # 首页
├── about.html # 关于我们
├── poem.html # 藏头诗页面
└── css/
└── index.css # 样式文件
harmonyos/entry/src/main/resources/rawfile/www/
├── translate.html # 翻译页面(同步)
├── js/
│ └── translate.js # 翻译功能脚本(同步)
└── ...
部署说明
1. 开发环境
bash
# 添加浏览器平台(用于测试)
hcordova platform add browser
# 运行浏览器预览
hcordova run browser
2. 生产环境
bash
# 构建 HarmonyOS 应用
hcordova build harmonyos
# 构建 Android 应用
hcordova build android
# 构建 iOS 应用(仅 macOS)
hcordova build ios
3. 配置检查
- ✅ 检查
config.xml中的 CSP 配置 - ✅ 确认 API 域名在白名单中
- ✅ 测试 Token 获取功能
- ✅ 验证表单验证逻辑
测试建议
1. 功能测试
- 表单验证测试(文本、Token)
- API 调用测试(正常情况、错误情况)
- Token 存储测试(保存、加载)
- 弹窗功能测试(打开、关闭、ESC 键)
- 语言选择测试(各种语言组合)
- 自动检测测试(不同语言的文本)
2. 兼容性测试
- 不同浏览器测试(Chrome、Safari、Firefox)
- 移动设备测试(iOS、Android、HarmonyOS)
- 不同屏幕尺寸测试
3. 性能测试
- API 响应时间
- 页面加载速度
- 内存使用情况
- 长文本处理性能
扩展功能建议
1. 历史记录
javascript
// 保存翻译历史
function saveHistory(translationData) {
const history = JSON.parse(localStorage.getItem('translate_history') || '[]');
history.unshift({
src: translationData.src,
dst: translationData.dst,
from: translationData.from,
to: translationData.to,
timestamp: Date.now()
});
// 只保留最近 50 条
if (history.length > 50) {
history.pop();
}
localStorage.setItem('translate_history', JSON.stringify(history));
}
2. 收藏功能
javascript
// 收藏翻译
function favoriteTranslation(translationData) {
const favorites = JSON.parse(localStorage.getItem('translate_favorites') || '[]');
favorites.push(translationData);
localStorage.setItem('translate_favorites', JSON.stringify(favorites));
}
3. 复制功能
javascript
// 复制翻译结果
function copyTranslation(text) {
if (navigator.clipboard) {
navigator.clipboard.writeText(text).then(() => {
alert('已复制到剪贴板');
});
} else {
// 兼容旧浏览器
const textarea = document.createElement('textarea');
textarea.value = text;
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
alert('已复制到剪贴板');
}
}
4. 语音朗读
javascript
// 使用 Web Speech API 朗读翻译结果
function speakText(text, lang) {
if ('speechSynthesis' in window) {
const utterance = new SpeechSynthesisUtterance(text);
utterance.lang = lang; // 设置语言
speechSynthesis.speak(utterance);
}
}
5. 快速切换语言
javascript
// 添加语言交换按钮
function swapLanguages() {
const fromSelect = document.getElementById('from');
const toSelect = document.getElementById('to');
const temp = fromSelect.value;
fromSelect.value = toSelect.value;
toSelect.value = temp;
}
总结
本文详细介绍了如何在 Cordova 应用中实现文本翻译功能,包括:
- ✅ 完整的实现方案:从页面设计到 API 集成
- ✅ 用户体验优化:表单验证、加载提示、错误处理
- ✅ Token 管理:自动保存和获取引导
- ✅ 响应式设计:完美适配各种设备
- ✅ 最佳实践:代码组织、错误处理、性能优化
关键技术点
- Fetch API:现代化的网络请求方式
- LocalStorage:客户端数据持久化
- Modal 弹窗:良好的用户交互体验
- CSP 配置:安全策略配置
- 响应式 CSS:移动端适配
- 语言映射:友好的语言名称显示
项目亮点
- 🌍 多语言支持:支持 30+ 种语言的翻译
- 🤖 自动检测:智能识别输入文本的语言
- 🎨 美观的 UI 设计:渐变背景、阴影效果、流畅动画
- 🔒 完善的错误处理:网络错误、API 错误、用户输入错误
- 💾 智能的 Token 管理:自动保存、一键获取
- 📱 完美的移动端适配:响应式布局、触摸优化
- ⚡ 良好的性能:快速响应、流畅交互
应用场景
- 学习辅助:翻译外语学习材料
- 商务沟通:跨语言交流
- 旅游出行:实时翻译
- 文档处理:批量文本翻译
- 内容创作:多语言内容生成
通过本文的指导,您可以快速实现一个功能完整、用户体验良好的翻译应用。希望本文对您的开发工作有所帮助!
作者 : 坚果派开发团队
最后更新 : 2025年
版本: 1.0
参考资源: