添加多国语言支持

This commit is contained in:
VinJay
2025-02-18 19:33:07 +08:00
parent 140aab8999
commit d5594d01a3
12 changed files with 206 additions and 27 deletions

View File

@@ -135,3 +135,31 @@ idf_component_register(SRCS ${SOURCES}
target_compile_definitions(${COMPONENT_LIB}
PRIVATE BOARD_TYPE=\"${BOARD_TYPE}\"
)
# 根据Kconfig选择语言目录
if(CONFIG_LANGUAGE_ZH)
set(LANG_DIR "zh")
elseif(CONFIG_LANGUAGE_EN)
set(LANG_DIR "en-US")
endif()
# 定义生成路径
set(LANG_JSON "${CMAKE_CURRENT_SOURCE_DIR}/assets/${LANG_DIR}/language.json")
set(LANG_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/assets/lang_config.h")
# 添加生成规则
add_custom_command(
OUTPUT ${LANG_HEADER}
COMMAND python3 ${PROJECT_DIR}/scripts/gen_lang.py
--input "${LANG_JSON}"
--output "${LANG_HEADER}"
DEPENDS
${LANG_JSON}
${PROJECT_DIR}/scripts/gen_lang.py
COMMENT "Generating ${LANG_DIR} language config"
)
# 强制建立生成依赖
add_custom_target(lang_header ALL
DEPENDS ${LANG_HEADER}
)

View File

@@ -6,6 +6,20 @@ config OTA_VERSION_URL
help
The application will access this URL to check for updates.
choice
prompt "语言选择"
default LANGUAGE_ZH
help
Select device display language
config LANGUAGE_ZH
bool "Chinese"
config LANGUAGE_EN
bool "English"
endchoice
choice CONNECTION_TYPE
prompt "Connection Type"
default CONNECTION_TYPE_MQTT_UDP

View File

@@ -1,6 +1,7 @@
#include "application.h"
#include "board.h"
#include "display.h"
#include "ssd1306_display.h"
#include "system_info.h"
#include "ml307_ssl_transport.h"
#include "audio_codec.h"
@@ -9,6 +10,7 @@
#include "font_awesome_symbols.h"
#include "iot/thing_manager.h"
#include "assets/zh/binary.h"
#include "assets/lang_config.h"
#include <cstring>
#include <esp_log.h>
@@ -117,7 +119,7 @@ void Application::CheckNewVersion() {
// No new version, mark the current version as valid
ota_.MarkCurrentVersionValid();
display->ShowNotification("版本 " + ota_.GetCurrentVersion());
display->ShowNotification(Lang::Strings::VERSION + " " + ota_.GetCurrentVersion());
if (ota_.HasActivationCode()) {
// Activation code is valid
@@ -218,7 +220,7 @@ void Application::ToggleChatState() {
if (device_state_ == kDeviceStateIdle) {
SetDeviceState(kDeviceStateConnecting);
if (!protocol_->OpenAudioChannel()) {
Alert("ERROR", "无法建立音频通道", "sad");
Alert("ERROR", Lang::Strings::UNABLE_TO_ESTABLISH_AUDIO_CHANNEL, "sad");
SetDeviceState(kDeviceStateIdle);
return;
}
@@ -252,7 +254,7 @@ void Application::StartListening() {
SetDeviceState(kDeviceStateConnecting);
if (!protocol_->OpenAudioChannel()) {
SetDeviceState(kDeviceStateIdle);
Alert("ERROR", "无法建立音频通道", "sad");
Alert("ERROR", Lang::Strings::UNABLE_TO_ESTABLISH_AUDIO_CHANNEL, "sad");
return;
}
}
@@ -326,7 +328,7 @@ void Application::Start() {
board.StartNetwork();
// Initialize the protocol
display->SetStatus("加载协议...");
display->SetStatus(Lang::Strings::LOADING_PROTOCOL + "...");
#ifdef CONFIG_CONNECTION_TYPE_WEBSOCKET
protocol_ = std::make_unique<WebsocketProtocol>();
#else
@@ -662,18 +664,18 @@ void Application::SetDeviceState(DeviceState state) {
switch (state) {
case kDeviceStateUnknown:
case kDeviceStateIdle:
display->SetStatus("待命");
display->SetStatus(Lang::Strings::STANDING_BY);
display->SetEmotion("neutral");
#ifdef CONFIG_USE_AUDIO_PROCESSING
audio_processor_.Stop();
#endif
break;
case kDeviceStateConnecting:
display->SetStatus("连接中...");
display->SetStatus(Lang::Strings::CONNECTING+"...");
display->SetChatMessage("system", "");
break;
case kDeviceStateListening:
display->SetStatus("聆听中...");
display->SetStatus(Lang::Strings::LISTENING+"...");
display->SetEmotion("neutral");
ResetDecoder();
opus_encoder_->ResetState();
@@ -683,7 +685,7 @@ void Application::SetDeviceState(DeviceState state) {
UpdateIotStates();
break;
case kDeviceStateSpeaking:
display->SetStatus("说话中...");
display->SetStatus(Lang::Strings::SPEAKING+"...");
ResetDecoder();
codec->EnableOutput(true);
#if CONFIG_USE_AUDIO_PROCESSING

View File

@@ -0,0 +1,34 @@
{
"language": {
"type" :"en"
},
"strings": {
"VERSION": "Version",
"LOADING_PROTOCOL":"Loading Protocol",
"INITIALIZING":"Initializing",
"NOTICE":"Notice",
"STANDING_BY":"Standing By",
"CONNECT":"Connect",
"CONNECTING":"Connecting",
"CONNECTION_SUCCESSFUL":"Connection Successful",
"LISTENING":"Listening",
"SPEAKING":"Speaking",
"UNABLE_TO_CONNECT_TO_SERVICE":"Unable to connect to service",
"WAITING_FOR_RESPONSE_TIMEOUT":"Waiting for response timeout",
"SENDING_FAILED_PLEASE_CHECK_THE_NETWORK":"Sending failed, please check the network",
"CONNECT_MOBILE_PHONE_TO_HOTSPOT":"Connect mobile phone to hotspot",
"ACCESS_VIA_BROWSER":"Access via browser",
"WIFI_CONFIGURATION_MODE":"Wi-Fi Configuration Mode",
"SCANNING_WIFI":"Scanning Wi-Fi",
"UNABLE_TO_ESTABLISH_AUDIO_CHANNEL": "Unable to establish audio channel",
"TEST":"Test"
}
}

View File

@@ -0,0 +1,34 @@
{
"language": {
"type" :"zh"
},
"strings": {
"VERSION": "版本",
"LOADING_PROTOCOL":"加载协议",
"INITIALIZING":"正在初始化",
"NOTICE":"通知",
"STANDING_BY":"待命",
"CONNECT":"连接",
"CONNECTING":"连接中",
"CONNECTION_SUCCESSFUL":"连接成功",
"LISTENING":"聆听中",
"SPEAKING":"说话中",
"UNABLE_TO_CONNECT_TO_SERVICE":"无法连接服务",
"WAITING_FOR_RESPONSE_TIMEOUT":"等待响应超时",
"SENDING_FAILED_PLEASE_CHECK_THE_NETWORK":"发送失败,请检查网络",
"CONNECT_MOBILE_PHONE_TO_HOTSPOT":"手机连接热点",
"ACCESS_VIA_BROWSER":"浏览器访问",
"WIFI_CONFIGURATION_MODE":"配网模式",
"SCANNING_WIFI":"扫描 WIFI",
"UNABLE_TO_ESTABLISH_AUDIO_CHANNEL": "无法建立音频通道",
"TEST":"测试"
}
}

View File

@@ -20,6 +20,7 @@
#include <wifi_station.h>
#include <wifi_configuration_ap.h>
#include <ssid_manager.h>
#include "assets/lang_config.h"
static const char *TAG = "WifiBoard";
@@ -45,14 +46,14 @@ void WifiBoard::EnterWifiConfigMode() {
wifi_ap.Start();
// 显示 WiFi 配置 AP 的 SSID 和 Web 服务器 URL
std::string hint = "手机连接热点 ";
std::string hint = Lang::Strings::CONNECT_MOBILE_PHONE_TO_HOTSPOT + " ";
hint += wifi_ap.GetSsid();
hint += "\n浏览器访问 ";
hint += "\n"+ Lang::Strings::ACCESS_VIA_BROWSER + " ";
hint += wifi_ap.GetWebServerUrl();
hint += "\n\n";
// 播报配置 WiFi 的提示
application.Alert("配网模式", hint, "", std::string_view(p3_wificonfig_start, p3_wificonfig_end - p3_wificonfig_start));
application.Alert(Lang::Strings::WIFI_CONFIGURATION_MODE, hint, "", std::string(p3_wificonfig_start, p3_wificonfig_end - p3_wificonfig_start));
// Wait forever until reset after configuration
while (true) {
@@ -82,15 +83,15 @@ void WifiBoard::StartNetwork() {
auto& wifi_station = WifiStation::GetInstance();
wifi_station.OnScanBegin([this]() {
auto display = Board::GetInstance().GetDisplay();
display->ShowNotification("扫描 WiFi...", 30000);
display->ShowNotification(Lang::Strings::SCANNING_WIFI, 30000);
});
wifi_station.OnConnect([this](const std::string& ssid) {
auto display = Board::GetInstance().GetDisplay();
display->ShowNotification(std::string("连接 ") + ssid + "...", 30000);
display->ShowNotification(std::string(Lang::Strings::CONNECT + " ") + ssid + "...", 30000);
});
wifi_station.OnConnected([this](const std::string& ssid) {
auto display = Board::GetInstance().GetDisplay();
display->ShowNotification(std::string("已连接 ") + ssid);
display->ShowNotification(std::string(Lang::Strings::CONNECTION_SUCCESSFUL) + ssid);
});
wifi_station.Start();
@@ -171,7 +172,7 @@ void WifiBoard::ResetWifiConfiguration() {
Settings settings("wifi", true);
settings.SetInt("force_ap", 1);
}
GetDisplay()->ShowNotification("进入配网模式...");
GetDisplay()->ShowNotification("Enter the network configuration mode...");
vTaskDelay(pdMS_TO_TICKS(1000));
// Reboot the device
esp_restart();

View File

@@ -7,6 +7,7 @@
#include <vector>
#include <esp_lvgl_port.h>
#include <esp_timer.h>
#include "assets/lang_config.h"
#include "board.h"
@@ -256,13 +257,13 @@ void LcdDisplay::SetupUI() {
notification_label_ = lv_label_create(status_bar_);
lv_obj_set_flex_grow(notification_label_, 1);
lv_obj_set_style_text_align(notification_label_, LV_TEXT_ALIGN_CENTER, 0);
lv_label_set_text(notification_label_, "通知");
lv_label_set_text(notification_label_, (Lang::Strings::NOTICE).c_str());
lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
status_label_ = lv_label_create(status_bar_);
lv_obj_set_flex_grow(status_label_, 1);
lv_label_set_long_mode(status_label_, LV_LABEL_LONG_SCROLL_CIRCULAR);
lv_label_set_text(status_label_, "正在初始化");
lv_label_set_text(status_label_,(Lang::Strings::INITIALIZING + "...").c_str());
lv_obj_set_style_text_align(status_label_, LV_TEXT_ALIGN_CENTER, 0);
mute_label_ = lv_label_create(status_bar_);

View File

@@ -6,6 +6,7 @@
#include <esp_lcd_panel_ops.h>
#include <esp_lcd_panel_vendor.h>
#include <esp_lvgl_port.h>
#include "assets/lang_config.h"
#define TAG "Ssd1306Display"
@@ -220,12 +221,12 @@ void Ssd1306Display::SetupUI_128x64() {
notification_label_ = lv_label_create(status_bar_);
lv_obj_set_flex_grow(notification_label_, 1);
lv_obj_set_style_text_align(notification_label_, LV_TEXT_ALIGN_CENTER, 0);
lv_label_set_text(notification_label_, "通知");
lv_label_set_text(notification_label_, (Lang::Strings::NOTICE).c_str());
lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
status_label_ = lv_label_create(status_bar_);
lv_obj_set_flex_grow(status_label_, 1);
lv_label_set_text(status_label_, "正在初始化");
lv_label_set_text(status_label_,(Lang::Strings::INITIALIZING + "...").c_str());
lv_obj_set_style_text_align(status_label_, LV_TEXT_ALIGN_CENTER, 0);
mute_label_ = lv_label_create(status_bar_);
@@ -295,10 +296,10 @@ void Ssd1306Display::SetupUI_128x32() {
status_label_ = lv_label_create(status_bar_);
lv_obj_set_style_pad_left(status_label_, 2, 0);
lv_label_set_text(status_label_, "正在初始化");
lv_label_set_text(status_label_,(Lang::Strings::INITIALIZING + "...").c_str());
notification_label_ = lv_label_create(status_bar_);
lv_label_set_text(notification_label_, "通知");
lv_label_set_text(notification_label_, (Lang::Strings::NOTICE).c_str());
lv_obj_set_style_pad_left(notification_label_, 2, 0);
lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);

View File

@@ -8,6 +8,7 @@
#include <ml307_udp.h>
#include <cstring>
#include <arpa/inet.h>
#include "assets/lang_config.h"
#define TAG "MQTT"
@@ -87,7 +88,7 @@ bool MqttProtocol::StartMqttClient() {
if (!mqtt_->Connect(endpoint_, 8883, client_id_, username_, password_)) {
ESP_LOGE(TAG, "Failed to connect to endpoint");
if (on_network_error_ != nullptr) {
on_network_error_("无法连接服务");
on_network_error_(Lang::Strings::UNABLE_TO_CONNECT_TO_SERVICE);
}
return false;
}
@@ -103,7 +104,7 @@ void MqttProtocol::SendText(const std::string& text) {
if (!mqtt_->Publish(publish_topic_, text)) {
ESP_LOGE(TAG, "Failed to publish message");
if (on_network_error_ != nullptr) {
on_network_error_("发送失败,请检查网络");
on_network_error_(Lang::Strings::SENDING_FAILED_PLEASE_CHECK_THE_NETWORK);
}
}
}
@@ -178,7 +179,7 @@ bool MqttProtocol::OpenAudioChannel() {
if (!(bits & MQTT_PROTOCOL_SERVER_HELLO_EVENT)) {
ESP_LOGE(TAG, "Failed to receive server hello");
if (on_network_error_ != nullptr) {
on_network_error_("等待响应超时");
on_network_error_(Lang::Strings::WAITING_FOR_RESPONSE_TIMEOUT);
}
return false;
}

View File

@@ -7,6 +7,7 @@
#include <cJSON.h>
#include <esp_log.h>
#include <arpa/inet.h>
#include "assets/lang_config.h"
#define TAG "WS"
@@ -98,7 +99,7 @@ bool WebsocketProtocol::OpenAudioChannel() {
if (!websocket_->Connect(url.c_str())) {
ESP_LOGE(TAG, "Failed to connect to websocket server");
if (on_network_error_ != nullptr) {
on_network_error_("无法连接服务");
on_network_error_(Lang::Strings::UNABLE_TO_CONNECT_TO_SERVICE);
}
return false;
}
@@ -119,7 +120,7 @@ bool WebsocketProtocol::OpenAudioChannel() {
if (!(bits & WEBSOCKET_PROTOCOL_SERVER_HELLO_EVENT)) {
ESP_LOGE(TAG, "Failed to receive server hello");
if (on_network_error_ != nullptr) {
on_network_error_("等待响应超时");
on_network_error_(Lang::Strings::WAITING_FOR_RESPONSE_TIMEOUT);
}
return false;
}