Cordova 开发鸿蒙PC应用翻译应用实现技术博客

Cordova 开发鸿蒙PC应用翻译应用实现技术博客

目录

  1. 项目概述
  2. 技术选型
  3. 功能需求分析
  4. 实现步骤
  5. 核心代码解析
  6. [API 集成详解](#API 集成详解)
  7. 用户体验优化
  8. 常见问题与解决方案
  9. 最佳实践
  10. 总结

项目概述

翻译应用是一个基于 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 zhauto
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: 跨域请求失败

原因:浏览器的同源策略限制

解决方案

  1. 配置正确的 CSP 策略
  2. 使用 fetch API(Cordova 环境支持跨域)
  3. 确保 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 自动检测可能误判

解决方案

  1. 提供手动选择源语言的选项
  2. 默认使用自动检测,但允许用户覆盖
  3. 在结果中显示检测到的语言,让用户确认
javascript 复制代码
// 如果自动检测结果不准确,用户可以手动选择源语言
<select id="from" name="from">
    <option value="auto">自动检测</option>
    <option value="zh" selected>中文</option>
    <!-- 其他语言选项 -->
</select>

问题 4: Token 丢失

原因:浏览器清除缓存或 localStorage 被清空

解决方案

  1. 使用 localStorage 持久化存储
  2. 添加 Token 输入提示
  3. 提供快速获取 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 应用中实现文本翻译功能,包括:

  1. 完整的实现方案:从页面设计到 API 集成
  2. 用户体验优化:表单验证、加载提示、错误处理
  3. Token 管理:自动保存和获取引导
  4. 响应式设计:完美适配各种设备
  5. 最佳实践:代码组织、错误处理、性能优化

关键技术点

  • Fetch API:现代化的网络请求方式
  • LocalStorage:客户端数据持久化
  • Modal 弹窗:良好的用户交互体验
  • CSP 配置:安全策略配置
  • 响应式 CSS:移动端适配
  • 语言映射:友好的语言名称显示

项目亮点

  • 🌍 多语言支持:支持 30+ 种语言的翻译
  • 🤖 自动检测:智能识别输入文本的语言
  • 🎨 美观的 UI 设计:渐变背景、阴影效果、流畅动画
  • 🔒 完善的错误处理:网络错误、API 错误、用户输入错误
  • 💾 智能的 Token 管理:自动保存、一键获取
  • 📱 完美的移动端适配:响应式布局、触摸优化
  • 良好的性能:快速响应、流畅交互

应用场景

  • 学习辅助:翻译外语学习材料
  • 商务沟通:跨语言交流
  • 旅游出行:实时翻译
  • 文档处理:批量文本翻译
  • 内容创作:多语言内容生成

通过本文的指导,您可以快速实现一个功能完整、用户体验良好的翻译应用。希望本文对您的开发工作有所帮助!


作者 : 坚果派开发团队
最后更新 : 2025年
版本: 1.0

参考资源

相关推荐
大师兄66682 小时前
Qt-for-鸿蒙PC-Electron应用鸿蒙平台白屏问题修复实战
qt·electron·harmonyos
国服第二切图仔2 小时前
Electron 鸿蒙pc开发环境搭建完整保姆级教程(window)
javascript·electron·harmonyos
啃火龙果的兔子3 小时前
如何控制kotlin项目back的时候,只回退webview的路由
开发语言·kotlin·harmonyos
lqj_本人4 小时前
HarmonyOS + Cordova:在线资源加载与拦截缓存问题排查
harmonyos
IT考试认证5 小时前
华为人工智能认证 HCIA-AI Solution H13-313 题库
人工智能·华为·题库·hcia-ai·h13-313
7***37455 小时前
HarmonyOS分布式能力的核心技术
分布式·华为·harmonyos
不爱吃糖的程序媛6 小时前
Cordova 定位功能在鸿蒙上的实现技术博客
华为·harmonyos
t***L2666 小时前
HarmonyOS国际化
华为·harmonyos
国霄6 小时前
(6)Kotlin/Js For Harmony——ArkTs 开发工具套件
kotlin·harmonyos