DEV Community

SameX
SameX

Posted on

鸿蒙多语言智能输入法设计:动态切换子类型与实时翻译功能

本文旨在深入探讨多语言智能输入法的设计与实现,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及原作者。

在全球化的今天,多语言智能输入法成为了人们跨语言交流的重要工具。它不仅需要支持多种语言的输入,还应具备便捷的切换功能和实时翻译能力,以满足用户在不同场景下的需求。本文将详细介绍如何在华为鸿蒙HarmonyOS Next系统(API12)中设计并实现这样一个多语言智能输入法应用,包括项目需求分析、架构设计、关键技术实现以及数据一致性和错误处理等方面。

一、项目需求与设计分析

(一)用户需求

用户在使用多语言智能输入法时,期望能够轻松地在不同语言的键盘布局之间进行切换,例如在中文和英文输入法之间快速切换。同时,用户输入的文本能够实时翻译成目标语言,无需手动触发翻译操作,提高交流效率。

(二)架构设计

为了实现上述需求,我们采用了分层架构设计。将输入法分为输入界面层、输入法核心层和翻译服务层。输入界面层负责展示不同语言的键盘布局,并接收用户输入;输入法核心层管理输入法的状态、处理用户输入事件以及与翻译服务层进行通信;翻译服务层负责调用翻译API进行文本翻译,并将结果返回给输入法核心层。这种解耦设计使得各层职责明确,易于维护和扩展。

二、多语言键盘布局与子类型切换

(一)配置多语言子类型

在鸿蒙系统中,我们通过 ohos_extension.input_method 来配置输入法的子类型。以下是一个简单的配置示例,假设我们支持中文和英文两种语言的子类型:

{
  "module": {
    "extensionAbilities": [
      {
        "description": "InputMethodExtDemo",
        "icon": "Smedia:icon",
        "name": "InputMethodExtAbility",
        "srcEntry": "./ets/InputMethodExtensionAbility/InputMethodService.ts",
        "type": "inputMethod",
        "exported": true,
        "metadata": [
          {
            "name": "ohos.extension.input_method",
            "resource": "Sprofile:input_method_config"
          }
        ]
      }
    ]
  },
  "subtypes": [
    {
      "icon": "Smedia:icon",
      "id": "InputMethodExtAbility",
      "label": "$string:english",
      "locale": "en-US",
      "mode": "lower"
    },
    {
      "icon": "Smedia:icon",
      "id": "InputMethodExtAbility1",
      "label": "$string:chinese",
      "locale": "zh-CN",
      "mode": "lower"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

(二)实现子类型切换接口

在输入法应用中,我们使用 switchCurrentInputMethodSubtype 接口来实现子类型的切换。以下是一个示例代码:

import { InputMethodSubtype, inputMethod } from '@kit.IMEKit';

export class KeyboardController {
  async switchCurrentInputMethodSubtype() {
    let subTypes = await inputMethod.getSetting().listCurrentInputMethodSubtype();
    let currentSubType = inputMethod.getCurrentInputMethodSubtype();
    for (let i = 0; i < subTypes.length; i++) {
      if (subTypes[i].id!== currentSubType.id) {
        await inputMethod.switchCurrentInputMethodSubtype(subTypes[i]);
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

(三)监听 setSubtype 事件

为了根据不同的子类型加载相应的输入界面,我们需要监听 setSubtype 事件。以下是示例代码:

import { InputMethodSubtype, inputMethodEngine, inputMethod } from '@kit.IMEKit';

export class KeyboardController {
  async handleSubtypeChange() {
    let panel: inputMethodEngine.Panel;
    let inputMethodAbility: inputMethodEngine.InputMethodAbility = inputMethodEngine.getInputMethodAbility();
    inputMethodAbility.on('setSubtype', (inputMethodSubtype: InputMethodSubtype) => {
      if (inputMethodSubtype.id === 'InputMethodExtAbility') {
        panel.setUiContent('pages/Index');
      } else if (inputMethodSubtype.id === 'InputMethodExtAbility1') {
        panel.setUiContent('pages/Index1');
      }
    });
  }
}
Enter fullscreen mode Exit fullscreen mode

三、实时翻译功能模块设计与实现

(一)使用异步任务管理翻译请求

为了避免翻译请求阻塞用户输入,我们使用异步任务来管理翻译请求。在用户输入文本时,我们触发一个异步翻译任务,将文本发送到翻译服务层进行翻译。以下是一个简单的异步任务示例(使用 Promise):

async function translateText(text: string): Promise<string> {
  return new Promise((resolve, reject) => {
    // 这里模拟一个异步翻译操作,实际应用中应调用真实的翻译API
    setTimeout(() => {
      resolve(`翻译结果: ${text}`);
    }, 1000);
  });
}
Enter fullscreen mode Exit fullscreen mode

(二)实现跨进程调用翻译API

在鸿蒙系统中,输入法应用与翻译服务可能运行在不同的进程中,因此需要实现跨进程通信来调用翻译API。我们可以使用系统提供的进程间通信机制(如 Ability 之间的通信)来实现。以下是一个简单的跨进程调用示例(假设翻译服务是一个 ServiceAbility):

import { FeatureAbility } from '@ohos.ability.featureAbility';

async function callTranslationService(text: string): Promise<string> {
  let want = {
    bundleName: 'com.example.translation',
    abilityName: 'TranslationServiceAbility'
  };
  try {
    let result = await FeatureAbility.callAbility(want, { text });
    return result;
  } catch (error) {
    console.error('翻译服务调用失败:', error);
    return '';
  }
}
Enter fullscreen mode Exit fullscreen mode

(三)获取翻译结果并返回输入法应用

当翻译服务完成翻译后,通过回调或消息机制将翻译结果返回给输入法应用。在输入法应用中,我们需要处理翻译结果并将其显示给用户。以下是一个简单的处理示例:

callTranslationService('Hello').then((result) => {
  console.log('翻译结果:', result);
  // 在输入界面显示翻译结果
});
Enter fullscreen mode Exit fullscreen mode

四、数据一致性与错误处理

(一)处理翻译过程中网络请求错误

在翻译过程中,可能会遇到网络请求错误或翻译服务不可用的情况。我们需要对这些错误进行处理,给用户提供友好的提示。例如:

callTranslationService('Hello').catch((error) => {
  console.error('翻译失败:', error);
  // 显示错误提示给用户,如弹出对话框提示“翻译失败,请检查网络连接”
});
Enter fullscreen mode Exit fullscreen mode

(二)确保用户输入的文本与翻译结果同步显示

为了确保用户输入的文本与翻译结果同步显示,我们需要在合适的时机更新输入界面。例如,在翻译结果返回后,及时将结果显示在输入框旁边或其他指定位置。同时,要处理好用户在翻译过程中继续输入文本的情况,避免出现显示混乱。

五、示例代码与架构图

(一)示例代码

以下是一个简化的多语言智能输入法应用的主要代码结构示例:

// InputMethodService.ts
import { Want } from '@kit.AbilityKit';
import keyboardController from './model/KeyboardController';
import { InputMethodExtensionAbility } from '@kit.IMEKit';

export default class InputDemoService extends InputMethodExtensionAbility {
  onCreate(want: Want): void {
    keyboardController.onCreate(this.context);
  }

  onDestroy(): void {
    keyboardController.onDestroy();
  }
}

// KeyboardController.ts
import { display } from '@kit.ArkUT';
import { inputMethodEngine, InputMethodExtensionContext } from '@kit.IMEKit';

const inputMethodAbility: inputMethodEngine.InputMethodAbility = inputMethodEngine.getInputMethodAbility();

export class KeyboardController {
  private mContext: InputMethodExtensionContext | undefined = undefined;
  private panel: inputMethodEngine.Panel | undefined = undefined;
  private textInputClient: inputMethodEngine.InputClient | undefined = undefined;
  private keyboardController: inputMethodEngine.KeyboardController | undefined = undefined;

  constructor() {}

  public onCreate(context: InputMethodExtensionContext): void {
    this.mContext = context;
    this.initWindow();
    this.registerListener();
  }

  public onDestroy(): void {
    this.unRegisterListener();
    if (this.panel) {
      this.panel.hide();
      inputMethodAbility.destroyPanel(this.panel);
    }
    if (this.mContext) {
      this.mContext.destroy();
    }
  }

  public insertText(text: string): void {
    if (this.textInputClient) {
      this.textInputClient.insertText(text);
      // 触发翻译任务
      this.translateText(text);
    }
  }

  public deleteForward(length: number): void {
    if (this.textInputClient) {
      this.textInputClient.deleteForward(length);
    }
  }

  private initWindow(): void {
    if (this.mContext === undefined) {
      return;
    }
    let dis = display.getDefaultDisplaySync();
    let dWidth = dis.width;
    let dHeight = dis.height;
    let keyHeightRate = 0.47;
    let keyHeight = dHeight * keyHeightRate;
    let nonBarPosition = dHeight - keyHeight;
    let panelInfo: inputMethodEngine.PanelInfo = {
      type: inputMethodEngine.PanelType.SOFT_KEYBOARD,
      flag: inputMethodEngine.PanelFlag.FLG_FIXED
    };
    inputMethodAbility.createPanel(this.mContext, panelInfo).then(async (inputPanel: inputMethodEngine.Panel) => {
      this.panel = inputPanel;
      if (this.panel) {
        await this.panel.resize(dWidth, keyHeight);
        await this.panel.moveTo(0, nonBarPosition);
        await this.panel.setUiContent('InputMethodExtensionAbility/pages/Index');
      }
    });
  }

  private registerListener(): void {
    this.registerInputListener();
  }

  private registerInputListener(): void {
    inputMethodAbility.on('inputStart', (kbController, textInputClient) => {
      this.textInputClient = textInputClient;
      this.keyboardController = kbController;
    });
    inputMethodAbility.on('inputStop', () => {
      this.onDestroy();
    });
  }

  private unRegisterListener(): void {
    inputMethodAbility.off('inputStart');
    inputMethodAbility.off('inputStop', () => {});
  }

  private async translateText(text: string): Promise<void> {
    try {
      let result = await callTranslationService(text);
      // 处理翻译结果并显示
      console.log('翻译结果:', result);
    } catch (error) {
      console.error('翻译失败:', error);
    }
  }
}

const keyboardController = new KeyboardController();
export default keyboardController;
Enter fullscreen mode Exit fullscreen mode

(二)架构图

以下是多语言智能输入法应用的架构图示意:

层次 功能描述
输入界面层 展示不同语言的键盘布局,接收用户输入,显示翻译结果。
输入法核心层 管理输入法状态,处理用户输入事件,调用翻译服务,更新输入界面。
翻译服务层 调用翻译API进行文本翻译,返回翻译结果给输入法核心层。

通过以上设计与实现,我们成功打造了一个多语言智能输入法应用,满足了用户在多语言输入和实时翻译方面的需求。在实际开发中,还可以进一步优化性能、增加更多语言支持以及完善用户体验等。希望本文能够为鸿蒙系统输入法开发提供有益的参考和借鉴。

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

Top comments (0)

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

Rather than just generating snippets, our agents understand your entire project context, can make decisions, use tools, and carry out tasks autonomously.

Read full post

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay