main
lbssad 5 months ago
parent 41046546da
commit 8ddc2f2e4f

@ -1,2 +0,0 @@
# 1-17

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

15
src/.gitignore vendored

@ -0,0 +1,15 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AndroidProjectSystem">
<option name="providerId" value="com.android.tools.idea.GradleProjectSystem" />
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="21" />
</component>
</project>

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetSelector">
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-11-14T19:29:26.954556Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="LocalEmulator" identifier="path=C:\Users\LENOVO\.android\avd\Pixel_9.avd" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState>
</selectionStates>
</component>
</project>

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DeviceTable">
<option name="columnSorters">
<list>
<ColumnSorterState>
<option name="column" value="API" />
<option name="order" value="DESCENDING" />
</ColumnSorterState>
</list>
</option>
</component>
</project>

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="CHOOSE_PER_TEST" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.9.23" />
</component>
</project>

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

@ -0,0 +1,323 @@
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectInspectionProfilesVisibleTreeState">
<entry key="Project Default">
<profile-state>
<expanded-state>
<State>
<id>Abstraction issuesJava</id>
</State>
<State>
<id>AccessibilityHTML</id>
</State>
<State>
<id>AiExcludeGemini</id>
</State>
<State>
<id>Android</id>
</State>
<State>
<id>Android Lint: Accessibility</id>
</State>
<State>
<id>Android Lint: Compliance</id>
</State>
<State>
<id>Android Lint: Correctness</id>
</State>
<State>
<id>Android Lint: Internationalization</id>
</State>
<State>
<id>Android Lint: Interoperability</id>
</State>
<State>
<id>Android Lint: Performance</id>
</State>
<State>
<id>Android Lint: Security</id>
</State>
<State>
<id>Android Lint: Usability</id>
</State>
<State>
<id>Assignment issuesJava</id>
</State>
<State>
<id>Best practisesGradle</id>
</State>
<State>
<id>C/C++</id>
</State>
<State>
<id>Class metricsJava</id>
</State>
<State>
<id>Class structureJava</id>
</State>
<State>
<id>ClassNaming conventionsJava</id>
</State>
<State>
<id>Cloning issuesJava</id>
</State>
<State>
<id>Code maturityJava</id>
</State>
<State>
<id>Code style issuesJava</id>
</State>
<State>
<id>CodePlugin DevKit</id>
</State>
<State>
<id>Compiler issuesJava</id>
</State>
<State>
<id>Control flow issuesJava</id>
</State>
<State>
<id>Data flowJava</id>
</State>
<State>
<id>Declaration redundancyJava</id>
</State>
<State>
<id>Description filePlugin DevKit</id>
</State>
<State>
<id>EditorConfig</id>
</State>
<State>
<id>EmbeddedPerformanceJava</id>
</State>
<State>
<id>EncapsulationJava</id>
</State>
<State>
<id>Error handlingJava</id>
</State>
<State>
<id>FunctionsC/C++</id>
</State>
<State>
<id>GPathGroovy</id>
</State>
<State>
<id>Gemini</id>
</State>
<State>
<id>General</id>
</State>
<State>
<id>GeneralC/C++</id>
</State>
<State>
<id>Gradle</id>
</State>
<State>
<id>Groovy</id>
</State>
<State>
<id>HTML</id>
</State>
<State>
<id>ImportsJava</id>
</State>
<State>
<id>Inheritance issuesJava</id>
</State>
<State>
<id>InitializationJava</id>
</State>
<State>
<id>Internationalization</id>
</State>
<State>
<id>InternationalizationJava</id>
</State>
<State>
<id>JNIAndroid</id>
</State>
<State>
<id>JUnit</id>
</State>
<State>
<id>JVM languages</id>
</State>
<State>
<id>Java</id>
</State>
<State>
<id>Java 11Java language level migration aidsJava</id>
</State>
<State>
<id>Java 21Java language level migration aidsJava</id>
</State>
<State>
<id>Java 5Java language level migration aidsJava</id>
</State>
<State>
<id>Java 7Java language level migration aidsJava</id>
</State>
<State>
<id>Java 8Java language level migration aidsJava</id>
</State>
<State>
<id>Java 9Java language level migration aidsJava</id>
</State>
<State>
<id>Java interop issuesKotlin</id>
</State>
<State>
<id>Java language level issuesJava</id>
</State>
<State>
<id>Java language level migration aidsJava</id>
</State>
<State>
<id>JavaBeans issuesJava</id>
</State>
<State>
<id>JavadocJava</id>
</State>
<State>
<id>Kotlin</id>
</State>
<State>
<id>LoggingJVM languages</id>
</State>
<State>
<id>LoggingJava</id>
</State>
<State>
<id>Markdown</id>
</State>
<State>
<id>MemoryJava</id>
</State>
<State>
<id>Method metricsJava</id>
</State>
<State>
<id>MethodNaming conventionsJava</id>
</State>
<State>
<id>MigrationKotlin</id>
</State>
<State>
<id>Modularization issuesJava</id>
</State>
<State>
<id>Naming conventionsJava</id>
</State>
<State>
<id>Nullability problemsProbable bugsJava</id>
</State>
<State>
<id>Numeric issuesJava</id>
</State>
<State>
<id>Objective-C</id>
</State>
<State>
<id>Other problemsKotlin</id>
</State>
<State>
<id>Packaging issuesJava</id>
</State>
<State>
<id>PerformanceJava</id>
</State>
<State>
<id>Plugin DevKit</id>
</State>
<State>
<id>Plugin descriptorPlugin DevKit</id>
</State>
<State>
<id>PortabilityJava</id>
</State>
<State>
<id>Probable bugsGradle</id>
</State>
<State>
<id>Probable bugsGroovy</id>
</State>
<State>
<id>Probable bugsJava</id>
</State>
<State>
<id>Probable bugsKotlin</id>
</State>
<State>
<id>Properties files</id>
</State>
<State>
<id>Properties filesJava</id>
</State>
<State>
<id>Redundant constructsKotlin</id>
</State>
<State>
<id>Reflective accessJava</id>
</State>
<State>
<id>RegExp</id>
</State>
<State>
<id>Resource managementJava</id>
</State>
<State>
<id>SecurityJava</id>
</State>
<State>
<id>Serialization issuesJava</id>
</State>
<State>
<id>ShrinkerAndroid</id>
</State>
<State>
<id>Static Analysis ToolsC/C++</id>
</State>
<State>
<id>Style issuesKotlin</id>
</State>
<State>
<id>StyleGroovy</id>
</State>
<State>
<id>Test frameworksJVM languages</id>
</State>
<State>
<id>Threading issuesGroovy</id>
</State>
<State>
<id>Threading issuesJava</id>
</State>
<State>
<id>Unused codeC/C++</id>
</State>
<State>
<id>Unused codeObjective-C</id>
</State>
<State>
<id>Validity issuesGradle</id>
</State>
<State>
<id>Verbose or redundant code constructsJava</id>
</State>
<State>
<id>VisibilityJava</id>
</State>
</expanded-state>
</profile-state>
</entry>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
<option value="com.intellij.execution.junit.PatternConfigurationProducer" />
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
<option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
</set>
</option>
</component>
</project>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings" defaultProject="true" />
</project>

@ -0,0 +1 @@
/build

@ -0,0 +1,57 @@
{
"agcgw_all": {
"SG": "connect-dra.dbankcloud.cn",
"SG_back": "connect-dra.hispace.hicloud.com",
"CN": "connect-drcn.dbankcloud.cn",
"CN_back": "connect-drcn.hispace.hicloud.com",
"RU": "connect-drru.hispace.dbankcloud.ru",
"RU_back": "connect-drru.hispace.dbankcloud.cn",
"DE": "connect-dre.dbankcloud.cn",
"DE_back": "connect-dre.hispace.hicloud.com"
},
"websocketgw_all": {
"SG": "connect-ws-dra.hispace.dbankcloud.cn",
"SG_back": "connect-ws-dra.hispace.dbankcloud.com",
"CN": "connect-ws-drcn.hispace.dbankcloud.cn",
"CN_back": "connect-ws-drcn.hispace.dbankcloud.com",
"RU": "connect-ws-drru.hispace.dbankcloud.ru",
"RU_back": "connect-ws-drru.hispace.dbankcloud.cn",
"DE": "connect-ws-dre.hispace.dbankcloud.cn",
"DE_back": "connect-ws-dre.hispace.dbankcloud.com"
},
"client": {
"cp_id": "10086000906180465",
"product_id": "461323198430990500",
"client_id": "1818854794438158016",
"client_secret": "2F4351B4753DE54BA6A16739AFB492E30A6E3E57E1ECA6247762FAF848C4CA7C",
"project_id": "461323198430990500",
"app_id": "115935909",
"api_key": "DgEDAB2Z+c0etbzB2qi1rq7NbdcidEmy0V1PPV2OZitqiZzhE4baa0oD32QPg7Y5BnlsnTWFqW0v1VLhOSEhYJUPSJ2Qxu4NDIt+Lg==",
"package_name": "com.translation.app"
},
"oauth_client": {
"client_id": "115935909",
"client_type": 1
},
"app_info": {
"app_id": "115935909",
"package_name": "com.translation.app"
},
"configuration_version": "3.0",
"appInfos": [
{
"package_name": "com.translation.app",
"client": {
"app_id": "115935909"
},
"app_info": {
"package_name": "com.translation.app",
"app_id": "115935909"
},
"oauth_client": {
"client_type": 1,
"client_id": "115935909"
}
}
]
}

@ -0,0 +1,271 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("com.huawei.agconnect")
}
// 全局依赖冲突解决方案
configurations.all {
resolutionStrategy {
// 强制排除所有 Support Library 依赖
eachDependency {
when (requested.group) {
"com.android.support" -> {
if (requested.name.contains("support-compat") ||
requested.name.contains("support-media-compat") ||
requested.name.contains("support-v4") ||
requested.name.contains("appcompat-v7")) {
useVersion("28.0.0")
}
}
}
}
// 强制使用 AndroidX
force(
"androidx.core:core:1.12.0",
"androidx.core:core-ktx:1.12.0",
"androidx.media:media:1.7.0",
"androidx.appcompat:appcompat:1.6.1",
"androidx.annotation:annotation:1.7.0"
)
// 优先使用项目模块
preferProjectModules()
}
}
android {
namespace = "com.translation.app"
compileSdk = 34
defaultConfig {
applicationId = "com.translation.app"
minSdk = 26
targetSdk = 34
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
// 添加构建配置字段
buildConfigField("String", "BUILD_TIME", "\"${System.currentTimeMillis()}\"")
buildConfigField("String", "HUAWEI_APP_ID", "\"115935909\"")
// 启用多dex支持
multiDexEnabled = true
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
debug {
isDebuggable = true
buildConfigField("boolean", "ENABLE_DEBUG_LOGS", "true")
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
isCoreLibraryDesugaringEnabled = true
}
kotlinOptions {
jvmTarget = "17"
}
buildFeatures {
viewBinding = true
buildConfig = true
}
packaging {
resources {
excludes += listOf(
"META-INF/DEPENDENCIES",
"META-INF/LICENSE",
"META-INF/LICENSE.txt",
"META-INF/NOTICE",
"META-INF/NOTICE.txt",
"META-INF/INDEX.LIST",
"META-INF/*.kotlin_module",
"**/android/support/v4/**",
"**/com/android/support/**"
)
pickFirsts += listOf(
"**",
"**/*.*"
)
}
}
}
dependencies {
// 全局排除 Support Library
configurations.all {
exclude(group = "com.android.support", module = "support-compat")
exclude(group = "com.android.support", module = "support-media-compat")
exclude(group = "com.android.support", module = "support-v4")
exclude(group = "com.android.support", module = "appcompat-v7")
exclude(group = "com.android.support", module = "support-annotations")
exclude(group = "com.android.support", module = "support-core-utils")
exclude(group = "com.android.support", module = "support-core-ui")
exclude(group = "com.android.support", module = "support-fragment")
}
// AndroidX Core
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.appcompat:appcompat:1.6.1")
// Material Design
implementation("com.google.android.material:material:1.10.0")
// UI Components
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.recyclerview:recyclerview:1.3.2")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
// Lifecycle
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
// Navigation
implementation("androidx.navigation:navigation-fragment-ktx:2.7.4")
implementation("androidx.navigation:navigation-ui-ktx:2.7.4")
// Network
implementation("com.squareup.okhttp3:okhttp:4.12.0")
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
// JSON Processing
implementation("com.google.code.gson:gson:2.10.1")
// 机器学习与自然语言处理
implementation("org.tensorflow:tensorflow-lite:2.14.0")
implementation("org.tensorflow:tensorflow-lite-support:0.4.4")
// 华为 ML Kit - 统一版本,避免冲突
implementation("com.huawei.hms:ml-computer-translate:3.11.0.302") {
exclude(group = "com.android.support")
}
implementation("com.huawei.hms:ml-computer-language-detection:3.11.0.302") {
exclude(group = "com.android.support")
}
// 其他华为服务
implementation("com.huawei.agconnect:agconnect-core:1.9.1.300")
// 数据库
implementation("androidx.room:room-runtime:2.6.0")
implementation("androidx.room:room-ktx:2.6.0")
annotationProcessor("androidx.room:room-compiler:2.6.0")
// 多dex支持
implementation("androidx.multidex:multidex:2.0.1")
// 异步处理
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
// Java 8+ API 反糖化支持
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4")
// 测试依赖
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
// Word 文档处理
implementation("org.apache.poi:poi:5.2.3") {
exclude(group = "com.android.support")
}
implementation("org.apache.poi:poi-ooxml:5.2.3") {
exclude(group = "com.android.support")
}
implementation("org.apache.xmlbeans:xmlbeans:5.1.1")
implementation("org.apache.commons:commons-compress:1.21")
implementation("commons-io:commons-io:2.11.0")
implementation("org.apache.poi:poi-scratchpad:5.2.3") {
exclude(group = "com.android.support")
}
// 添加必要的日志依赖
implementation("org.slf4j:slf4j-api:2.0.7")
implementation("org.slf4j:slf4j-simple:2.0.7")
// 补充的依赖
implementation("com.tom-roush:pdfbox-android:2.0.27.0") {
exclude(group = "com.android.support")
}
implementation("com.github.bumptech.glide:glide:4.16.0") {
exclude(group = "com.android.support")
}
annotationProcessor("com.github.bumptech.glide:compiler:4.16.0")
implementation("com.guolindev.permissionx:permissionx:1.7.1") {
exclude(group = "com.android.support")
}
implementation("com.github.dhaval2404:imagepicker:2.1") {
exclude(group = "com.android.support")
}
// 可选的增强功能
implementation("com.arthenica:ffmpeg-kit-full:4.5.1") {
exclude(group = "com.android.support")
}
implementation("id.zelory:compressor:3.0.1") {
exclude(group = "com.android.support")
}
// === 专业音频处理库 ===
// FFmpeg (功能最全面的音频处理)
implementation("com.arthenica:ffmpeg-kit-full:4.5.1") {
exclude(group = "com.android.support")
}
// Android MediaCodec (官方音频编解码)
implementation("androidx.media:media:1.7.0")
// 音频可视化库 - 使用兼容 AndroidX 的版本
implementation("com.gauravk.audiovisualizer:audiovisualizer:0.9.2") {
exclude(group = "com.android.support")
}
// 替代方案1使用更稳定的音频可视化库
implementation("com.gauravk.audiovisualizer:audiovisualizer:0.9.2") {
exclude(group = "com.android.support")
}
// 替代方案3使用官方的可视化组件
implementation("androidx.media3:media3-ui:1.2.0") {
exclude(group = "com.android.support")
}
// Android Audio Record/Playback
implementation("androidx.media3:media3-exoplayer:1.2.0") {
exclude(group = "com.android.support")
}
implementation("androidx.media3:media3-common:1.2.0") {
exclude(group = "com.android.support")
}
// 音频格式检测
implementation("org.apache.tika:tika-core:2.9.0") {
exclude(group = "com.android.support")
}
// 音频元数据读取
implementation("com.googlecode.mp4parser:isoparser:1.1.22") {
exclude(group = "com.android.support")
}
// 移除有问题的库
// implementation("com.github.Jay-Goo:WaveLineView:1.0.4") // 这个库引入了 Support Library
}

@ -0,0 +1,131 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# ========== 基本规则 ==========
-optimizations !code/simplification/cast,!field/*,!class/merging/*
-keepattributes *Annotation*
-keepattributes Signature
-keepattributes InnerClasses
-keepattributes EnclosingMethod
# 保留行号信息用于调试
-keepattributes SourceFile,LineNumberTable
# ========== 华为 HMS 混淆规则 ==========
-keep class com.huawei.hianalytics.**{*;}
-keep class com.huawei.updatesdk.**{*;}
-keep class com.huawei.hms.**{*;}
-keep class com.huawei.agconnect.**{*;}
# 保留 ML Kit 相关类
-keep class com.huawei.hms.ml.**{*;}
# 保留 HMS 核心类
-keep class * extends com.huawei.hms.common.api.Api.ApiOptions$HasOptions { *; }
-keep class * extends com.huawei.hms.common.api.Api.ApiOptions$NotRequiredOptions { *; }
-keep class * extends com.huawei.hms.common.api.Api.ApiOptions$Optional { *; }
# 保留 HMS 序列化类
-keepclasseswithmembers class * implements com.huawei.hms.common.internal.safeparcel.SafeParcelable {
public static final *** CREATOR;
}
# ========== 文档处理库规则 ==========
# PDFBox 规则
-keep class org.apache.pdfbox.** { *; }
-keep class com.tom_roush.pdfbox.** { *; }
# Apache POI 规则
-keep class org.apache.poi.** { *; }
-keep class org.apache.xmlbeans.** { *; }
-keep class schemas.microsoft.com.** { *; }
-keep class org.openxmlformats.** { *; }
# ICU4J 规则
-keep class com.ibm.icu.** { *; }
# Zip4j 规则
-keep class net.lingala.zip4j.** { *; }
# ========== 网络库规则 ==========
-keep class com.squareup.okhttp3.** { *; }
-keep class okhttp3.** { *; }
-keep class com.squareup.retrofit2.** { *; }
-keep class retrofit2.** { *; }
-keepattributes RuntimeVisibleAnnotations
-keepattributes RuntimeInvisibleAnnotations
-dontwarn okhttp3.**
-dontwarn retrofit2.**
-keepclasseswithmembers class * {
@retrofit2.http.* <methods>;
}
# ========== 项目特定规则 ==========
# 保留数据类(用于 RoomGson 等)
-keep class com.translation.model.** { *; }
-keep class com.translation.entity.** { *; }
-keep class com.translation.service.** { *; }
# 保留构建配置字段
-keepclassmembers class com.translation.BuildConfig {
public static final *;
}
# 保留 ViewBinding
-keep class * extends androidx.viewbinding.ViewBinding {
*;
}
# 保留协程相关
-keep class kotlinx.coroutines.** { *; }
# 保留 Glide 相关
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep class * extends com.bumptech.glide.module.AppGlideModule {
<init>(...);
}
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
# 保留 Room 相关
-keep class * extends androidx.room.RoomDatabase {
*;
}
# 保留序列化相关
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
# ========== 原生方法规则 ==========
-keepclasseswithmembers class * {
native <methods>;
}
# ========== 枚举规则 ==========
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# ========== 泛型规则 ==========
-keepattributes Signature
# ========== 资源规则 ==========
-keepclassmembers class **.R$* {
public static <fields>;
}

@ -0,0 +1,26 @@
package com.translation.app;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.translation.app", appContext.getPackageName());
}
}

@ -0,0 +1,160 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.translation.app">
<!-- 权限声明 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<!-- Android 13+ 分区存储权限 -->
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<!-- 华为 HMS 所需权限 -->
<uses-permission android:name="com.huawei.appmarket.service.commondata.permission.GET_COMMON_DATA" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- 可选:如果需要获取设备信息 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 添加必要的特性声明 -->
<uses-feature
android:name="android.hardware.microphone"
android:required="false" />
<uses-feature
android:name="android.hardware.wifi"
android:required="false" />
<application
android:name=".TranslationApp"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.TranslationApp"
android:requestLegacyExternalStorage="true"
android:usesCleartextTraffic="true"
tools:targetApi="31"
tools:ignore="GoogleAppIndexingWarning"
tools:replace="android:allowBackup">
<!-- 华为 AGConnect 配置 -->
<meta-data
android:name="com.huawei.hms.client.appid"
android:value="appid=你的应用ID" />
<meta-data
android:name="com.huawei.agconnect.app"
android:value="@string/agconnect_app_id" />
<!-- 华为 ML Kit 配置 -->
<meta-data
android:name="com.huawei.hms.ml.enable_mlkit_log"
android:value="true" />
<meta-data
android:name="com.huawei.hms.ml.enable_mlkit_monitor"
android:value="true" />
<!-- ML Kit 翻译服务配置 -->
<meta-data
android:name="com.huawei.hms.ml.translate.enable_service"
android:value="true" />
<!-- 华为分析服务配置 -->
<meta-data
android:name="com.huawei.hms.analytics.globalKey.autoReportEnabled"
android:value="true" />
<meta-data
android:name="com.huawei.hms.analytics.globalKey.autoInitEnabled"
android:value="true" />
<!-- HMS Core SDK 版本 -->
<meta-data
android:name="com.huawei.hms.version"
android:value="6.11.0.300" />
<!-- 修正 Activity 路径 -->
<activity
android:name="com.translation.activity.LoginActivity"
android:exported="true"
android:theme="@style/Theme.TranslationApp.Launcher"
android:screenOrientation="portrait"
android:configChanges="orientation|screenSize|keyboardHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- 主翻译页面 -->
<activity
android:name="com.translation.activity.MainTranslationActivity"
android:exported="false"
android:theme="@style/Theme.TranslationApp"
android:screenOrientation="portrait"
android:configChanges="orientation|screenSize|keyboardHidden" />
<!-- 历史记录页面 -->
<activity
android:name="com.translation.activity.HistoryActivity"
android:exported="false"
android:theme="@style/Theme.TranslationApp"
android:screenOrientation="portrait" />
<!-- 标签管理页面 -->
<activity
android:name="com.translation.activity.TagManagementActivity"
android:exported="false"
android:theme="@style/Theme.TranslationApp"
android:screenOrientation="portrait" />
<!-- 设置页面 -->
<activity
android:name="com.translation.activity.SettingsActivity"
android:exported="false"
android:theme="@style/Theme.TranslationApp"
android:screenOrientation="portrait" />
<!-- 标签记录页面 -->
<activity
android:name="com.translation.activity.TagRecordsActivity"
android:exported="false"
android:theme="@style/Theme.TranslationApp"
android:screenOrientation="portrait" />
<!-- 文件提供者 -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<!-- HMS Core 服务组件 -->
<service
android:name="com.huawei.hms.opendevice.OpenDeviceService"
android:exported="false" />
<service
android:name="com.huawei.hms.support.api.push.service.HmsMsgService"
android:exported="false">
<intent-filter>
<action android:name="com.huawei.push.action.MESSAGING_EVENT" />
</intent-filter>
</service>
</application>
</manifest>

@ -0,0 +1,35 @@
{
"fileName": "dictionary_de_zh.json",
"fileContent": {
"entries": [
{"source": "Hallo", "target": "你好"},
{"source": "Danke", "target": "谢谢"},
{"source": "Entschuldigung", "target": "对不起"},
{"source": "Auf Wiedersehen", "target": "再见"},
{"source": "Ja", "target": "是"},
{"source": "Nein", "target": "不"},
{"source": "Ich", "target": "我"},
{"source": "Du", "target": "你"},
{"source": "Er", "target": "他"},
{"source": "Sie", "target": "她"},
{"source": "Wir", "target": "我们"},
{"source": "Sie", "target": "他们"},
{"source": "Zeit", "target": "时间"},
{"source": "Heute", "target": "今天"},
{"source": "Morgen", "target": "明天"},
{"source": "Liebe", "target": "爱"},
{"source": "Familie", "target": "家庭"},
{"source": "Freund", "target": "朋友"},
{"source": "Schule", "target": "学校"},
{"source": "Arbeit", "target": "工作"},
{"source": "Computer", "target": "电脑"},
{"source": "Handy", "target": "手机"},
{"source": "Auto", "target": "汽车"},
{"source": "Geld", "target": "钱"},
{"source": "Musik", "target": "音乐"},
{"source": "Buch", "target": "书"},
{"source": "Wasser", "target": "水"},
{"source": "Essen", "target": "食物"}
]
}
}

@ -0,0 +1,30 @@
{
"entries": [
{"source": "hello", "target": "こんにちは"},
{"source": "world", "target": "世界"},
{"source": "thank you", "target": "ありがとう"},
{"source": "sorry", "target": "すみません"},
{"source": "goodbye", "target": "さようなら"},
{"source": "yes", "target": "はい"},
{"source": "no", "target": "いいえ"},
{"source": "time", "target": "時間"},
{"source": "today", "target": "今日"},
{"source": "tomorrow", "target": "明日"},
{"source": "love", "target": "愛"},
{"source": "friend", "target": "友達"},
{"source": "family", "target": "家族"},
{"source": "school", "target": "学校"},
{"source": "work", "target": "仕事"},
{"source": "computer", "target": "コンピューター"},
{"source": "phone", "target": "電話"},
{"source": "car", "target": "車"},
{"source": "money", "target": "お金"},
{"source": "music", "target": "音楽"},
{"source": "movie", "target": "映画"},
{"source": "book", "target": "本"},
{"source": "water", "target": "水"},
{"source": "food", "target": "食べ物"},
{"source": "coffee", "target": "コーヒー"},
{"source": "tea", "target": "お茶"}
]
}

@ -0,0 +1,89 @@
{
"entries": [
{"source": "hello", "target": "你好"},
{"source": "world", "target": "世界"},
{"source": "translation", "target": "翻译"},
{"source": "language", "target": "语言"},
{"source": "learn", "target": "学习"},
{"source": "work", "target": "工作"},
{"source": "time", "target": "时间"},
{"source": "today", "target": "今天"},
{"source": "tomorrow", "target": "明天"},
{"source": "thank you", "target": "谢谢"},
{"source": "sorry", "target": "对不起"},
{"source": "yes", "target": "是的"},
{"source": "no", "target": "不"},
{"source": "good", "target": "好"},
{"source": "bad", "target": "坏"},
{"source": "big", "target": "大"},
{"source": "small", "target": "小"},
{"source": "fast", "target": "快"},
{"source": "slow", "target": "慢"},
{"source": "hot", "target": "热"},
{"source": "cold", "target": "冷"},
{"source": "water", "target": "水"},
{"source": "food", "target": "食物"},
{"source": "love", "target": "爱"},
{"source": "family", "target": "家庭"},
{"source": "friend", "target": "朋友"},
{"source": "school", "target": "学校"},
{"source": "teacher", "target": "老师"},
{"source": "student", "target": "学生"},
{"source": "book", "target": "书"},
{"source": "computer", "target": "电脑"},
{"source": "phone", "target": "手机"},
{"source": "car", "target": "汽车"},
{"source": "house", "target": "房子"},
{"source": "city", "target": "城市"},
{"source": "country", "target": "国家"},
{"source": "people", "target": "人民"},
{"source": "government", "target": "政府"},
{"source": "economy", "target": "经济"},
{"source": "culture", "target": "文化"},
{"source": "history", "target": "历史"},
{"source": "science", "target": "科学"},
{"source": "technology", "target": "技术"},
{"source": "art", "target": "艺术"},
{"source": "music", "target": "音乐"},
{"source": "movie", "target": "电影"},
{"source": "sports", "target": "体育"},
{"source": "health", "target": "健康"},
{"source": "hospital", "target": "医院"},
{"source": "doctor", "target": "医生"},
{"source": "money", "target": "钱"},
{"source": "price", "target": "价格"},
{"source": "market", "target": "市场"},
{"source": "company", "target": "公司"},
{"source": "job", "target": "工作"},
{"source": "salary", "target": "工资"},
{"source": "travel", "target": "旅行"},
{"source": "airplane", "target": "飞机"},
{"source": "train", "target": "火车"},
{"source": "hotel", "target": "酒店"},
{"source": "restaurant", "target": "餐厅"},
{"source": "food", "target": "食物"},
{"source": "drink", "target": "饮料"},
{"source": "coffee", "target": "咖啡"},
{"source": "tea", "target": "茶"},
{"source": "fruit", "target": "水果"},
{"source": "apple", "target": "苹果"},
{"source": "banana", "target": "香蕉"},
{"source": "orange", "target": "橙色"},
{"source": "red", "target": "红色"},
{"source": "blue", "target": "蓝色"},
{"source": "green", "target": "绿色"},
{"source": "yellow", "target": "黄色"},
{"source": "black", "target": "黑色"},
{"source": "white", "target": "白色"},
{"source": "one", "target": "一"},
{"source": "two", "target": "二"},
{"source": "three", "target": "三"},
{"source": "four", "target": "四"},
{"source": "five", "target": "五"},
{"source": "six", "target": "六"},
{"source": "seven", "target": "七"},
{"source": "eight", "target": "八"},
{"source": "nine", "target": "九"},
{"source": "ten", "target": "十"}
]
}

@ -0,0 +1,35 @@
{
"fileName": "dictionary_es_zh.json",
"fileContent": {
"entries": [
{"source": "Hola", "target": "你好"},
{"source": "Gracias", "target": "谢谢"},
{"source": "Lo siento", "target": "对不起"},
{"source": "Adiós", "target": "再见"},
{"source": "Sí", "target": "是"},
{"source": "No", "target": "不"},
{"source": "Yo", "target": "我"},
{"source": "Tú", "target": "你"},
{"source": "Él", "target": "他"},
{"source": "Ella", "target": "她"},
{"source": "Nosotros", "target": "我们"},
{"source": "Ellos", "target": "他们"},
{"source": "Tiempo", "target": "时间"},
{"source": "Hoy", "target": "今天"},
{"source": "Mañana", "target": "明天"},
{"source": "Amor", "target": "爱"},
{"source": "Familia", "target": "家庭"},
{"source": "Amigo", "target": "朋友"},
{"source": "Escuela", "target": "学校"},
{"source": "Trabajo", "target": "工作"},
{"source": "Computadora", "target": "电脑"},
{"source": "Teléfono", "target": "手机"},
{"source": "Coche", "target": "汽车"},
{"source": "Dinero", "target": "钱"},
{"source": "Música", "target": "音乐"},
{"source": "Libro", "target": "书"},
{"source": "Agua", "target": "水"},
{"source": "Comida", "target": "食物"}
]
}
}

@ -0,0 +1,62 @@
{
"entries": [
{"source": "bonjour", "target": "你好"},
{"source": "merci", "target": "谢谢"},
{"source": "désolé", "target": "对不起"},
{"source": "au revoir", "target": "再见"},
{"source": "oui", "target": "是"},
{"source": "non", "target": "不"},
{"source": "je", "target": "我"},
{"source": "tu", "target": "你"},
{"source": "il", "target": "他"},
{"source": "elle", "target": "她"},
{"source": "nous", "target": "我们"},
{"source": "ils", "target": "他们"},
{"source": "ceci", "target": "这个"},
{"source": "cela", "target": "那个"},
{"source": "quoi", "target": "什么"},
{"source": "où", "target": "哪里"},
{"source": "pourquoi", "target": "为什么"},
{"source": "comment", "target": "如何"},
{"source": "temps", "target": "时间"},
{"source": "aujourd'hui", "target": "今天"},
{"source": "demain", "target": "明天"},
{"source": "hier", "target": "昨天"},
{"source": "amour", "target": "爱"},
{"source": "famille", "target": "家庭"},
{"source": "ami", "target": "朋友"},
{"source": "école", "target": "学校"},
{"source": "travail", "target": "工作"},
{"source": "manger", "target": "吃饭"},
{"source": "eau", "target": "水"},
{"source": "étudier", "target": "学习"},
{"source": "chine", "target": "中国"},
{"source": "france", "target": "法国"},
{"source": "paris", "target": "巴黎"},
{"source": "pékin", "target": "北京"},
{"source": "pomme", "target": "苹果"},
{"source": "banane", "target": "香蕉"},
{"source": "thé", "target": "茶"},
{"source": "café", "target": "咖啡"},
{"source": "livre", "target": "书"},
{"source": "ordinateur", "target": "电脑"},
{"source": "téléphone", "target": "手机"},
{"source": "voiture", "target": "汽车"},
{"source": "argent", "target": "钱"},
{"source": "musique", "target": "音乐"},
{"source": "film", "target": "电影"},
{"source": "grand", "target": "大"},
{"source": "petit", "target": "小"},
{"source": "bon", "target": "好"},
{"source": "mauvais", "target": "坏"},
{"source": "chaud", "target": "热"},
{"source": "froid", "target": "冷"},
{"source": "nouveau", "target": "新"},
{"source": "vieux", "target": "旧"},
{"source": "rouge", "target": "红色"},
{"source": "bleu", "target": "蓝色"},
{"source": "vert", "target": "绿色"},
{"source": "blanc", "target": "白色"},
{"source": "noir", "target": "黑色"}
]
}

@ -0,0 +1,35 @@
{
"fileName": "dictionary_it_zh.json",
"fileContent": {
"entries": [
{"source": "Ciao", "target": "你好"},
{"source": "Grazie", "target": "谢谢"},
{"source": "Scusa", "target": "对不起"},
{"source": "Arrivederci", "target": "再见"},
{"source": "Sì", "target": "是"},
{"source": "No", "target": "不"},
{"source": "Io", "target": "我"},
{"source": "Tu", "target": "你"},
{"source": "Lui", "target": "他"},
{"source": "Lei", "target": "她"},
{"source": "Noi", "target": "我们"},
{"source": "Loro", "target": "他们"},
{"source": "Tempo", "target": "时间"},
{"source": "Oggi", "target": "今天"},
{"source": "Domani", "target": "明天"},
{"source": "Amore", "target": "爱"},
{"source": "Famiglia", "target": "家庭"},
{"source": "Amico", "target": "朋友"},
{"source": "Scuola", "target": "学校"},
{"source": "Lavoro", "target": "工作"},
{"source": "Computer", "target": "电脑"},
{"source": "Telefono", "target": "手机"},
{"source": "Macchina", "target": "汽车"},
{"source": "Soldi", "target": "钱"},
{"source": "Musica", "target": "音乐"},
{"source": "Libro", "target": "书"},
{"source": "Acqua", "target": "水"},
{"source": "Cibo", "target": "食物"}
]
}
}

@ -0,0 +1,30 @@
{
"entries": [
{"source": "こんにちは", "target": "hello"},
{"source": "世界", "target": "world"},
{"source": "ありがとう", "target": "thank you"},
{"source": "すみません", "target": "sorry"},
{"source": "さようなら", "target": "goodbye"},
{"source": "はい", "target": "yes"},
{"source": "いいえ", "target": "no"},
{"source": "時間", "target": "time"},
{"source": "今日", "target": "today"},
{"source": "明日", "target": "tomorrow"},
{"source": "愛", "target": "love"},
{"source": "友達", "target": "friend"},
{"source": "家族", "target": "family"},
{"source": "学校", "target": "school"},
{"source": "仕事", "target": "work"},
{"source": "コンピューター", "target": "computer"},
{"source": "電話", "target": "phone"},
{"source": "車", "target": "car"},
{"source": "お金", "target": "money"},
{"source": "音楽", "target": "music"},
{"source": "映画", "target": "movie"},
{"source": "本", "target": "book"},
{"source": "水", "target": "water"},
{"source": "食べ物", "target": "food"},
{"source": "コーヒー", "target": "coffee"},
{"source": "お茶", "target": "tea"}
]
}

@ -0,0 +1,61 @@
{
"entries": [
{"source": "こんにちは", "target": "你好"},
{"source": "ありがとう", "target": "谢谢"},
{"source": "すみません", "target": "对不起"},
{"source": "さようなら", "target": "再见"},
{"source": "はい", "target": "是"},
{"source": "いいえ", "target": "不"},
{"source": "私", "target": "我"},
{"source": "あなた", "target": "你"},
{"source": "彼", "target": "他"},
{"source": "彼女", "target": "她"},
{"source": "私たち", "target": "我们"},
{"source": "彼ら", "target": "他们"},
{"source": "これ", "target": "这个"},
{"source": "それ", "target": "那个"},
{"source": "何", "target": "什么"},
{"source": "どこ", "target": "哪里"},
{"source": "なぜ", "target": "为什么"},
{"source": "時間", "target": "时间"},
{"source": "今日", "target": "今天"},
{"source": "明日", "target": "明天"},
{"source": "昨日", "target": "昨天"},
{"source": "愛", "target": "爱"},
{"source": "家族", "target": "家庭"},
{"source": "友達", "target": "朋友"},
{"source": "学校", "target": "学校"},
{"source": "仕事", "target": "工作"},
{"source": "食事", "target": "吃饭"},
{"source": "水", "target": "水"},
{"source": "勉強", "target": "学习"},
{"source": "中国", "target": "中国"},
{"source": "日本", "target": "日本"},
{"source": "東京", "target": "东京"},
{"source": "北京", "target": "北京"},
{"source": "りんご", "target": "苹果"},
{"source": "バナナ", "target": "香蕉"},
{"source": "お茶", "target": "茶"},
{"source": "コーヒー", "target": "咖啡"},
{"source": "本", "target": "书"},
{"source": "コンピューター", "target": "电脑"},
{"source": "携帯電話", "target": "手机"},
{"source": "車", "target": "汽车"},
{"source": "お金", "target": "钱"},
{"source": "音楽", "target": "音乐"},
{"source": "映画", "target": "电影"},
{"source": "大きい", "target": "大"},
{"source": "小さい", "target": "小"},
{"source": "良い", "target": "好"},
{"source": "悪い", "target": "坏"},
{"source": "熱い", "target": "热"},
{"source": "冷たい", "target": "冷"},
{"source": "新しい", "target": "新"},
{"source": "古い", "target": "旧"},
{"source": "赤", "target": "红色"},
{"source": "青", "target": "蓝色"},
{"source": "緑", "target": "绿色"},
{"source": "白", "target": "白色"},
{"source": "黒", "target": "黑色"}
]
}

@ -0,0 +1,61 @@
{
"entries": [
{"source": "안녕하세요", "target": "你好"},
{"source": "감사합니다", "target": "谢谢"},
{"source": "죄송합니다", "target": "对不起"},
{"source": "안녕히 가세요", "target": "再见"},
{"source": "네", "target": "是"},
{"source": "아니요", "target": "不"},
{"source": "나", "target": "我"},
{"source": "너", "target": "你"},
{"source": "그", "target": "他"},
{"source": "그녀", "target": "她"},
{"source": "우리", "target": "我们"},
{"source": "그들", "target": "他们"},
{"source": "이것", "target": "这个"},
{"source": "그것", "target": "那个"},
{"source": "무엇", "target": "什么"},
{"source": "어디", "target": "哪里"},
{"source": "왜", "target": "为什么"},
{"source": "시간", "target": "时间"},
{"source": "오늘", "target": "今天"},
{"source": "내일", "target": "明天"},
{"source": "어제", "target": "昨天"},
{"source": "사랑", "target": "爱"},
{"source": "가족", "target": "家庭"},
{"source": "친구", "target": "朋友"},
{"source": "학교", "target": "学校"},
{"source": "일", "target": "工作"},
{"source": "식사", "target": "吃饭"},
{"source": "물", "target": "水"},
{"source": "공부", "target": "学习"},
{"source": "중국", "target": "中国"},
{"source": "한국", "target": "韩国"},
{"source": "서울", "target": "首尔"},
{"source": "베이징", "target": "北京"},
{"source": "사과", "target": "苹果"},
{"source": "바나나", "target": "香蕉"},
{"source": "차", "target": "茶"},
{"source": "커피", "target": "咖啡"},
{"source": "책", "target": "书"},
{"source": "컴퓨터", "target": "电脑"},
{"source": "휴대폰", "target": "手机"},
{"source": "자동차", "target": "汽车"},
{"source": "돈", "target": "钱"},
{"source": "음악", "target": "音乐"},
{"source": "영화", "target": "电影"},
{"source": "크다", "target": "大"},
{"source": "작다", "target": "小"},
{"source": "좋다", "target": "好"},
{"source": "나쁘다", "target": "坏"},
{"source": "뜨겁다", "target": "热"},
{"source": "차갑다", "target": "冷"},
{"source": "새로운", "target": "新"},
{"source": "오래된", "target": "旧"},
{"source": "빨간색", "target": "红色"},
{"source": "파란색", "target": "蓝色"},
{"source": "초록색", "target": "绿色"},
{"source": "하얀색", "target": "白色"},
{"source": "검은색", "target": "黑色"}
]
}

@ -0,0 +1,35 @@
{
"fileName": "dictionary_pt_zh.json",
"fileContent": {
"entries": [
{"source": "Olá", "target": "你好"},
{"source": "Obrigado", "target": "谢谢"},
{"source": "Desculpe", "target": "对不起"},
{"source": "Adeus", "target": "再见"},
{"source": "Sim", "target": "是"},
{"source": "Não", "target": "不"},
{"source": "Eu", "target": "我"},
{"source": "Você", "target": "你"},
{"source": "Ele", "target": "他"},
{"source": "Ela", "target": "她"},
{"source": "Nós", "target": "我们"},
{"source": "Eles", "target": "他们"},
{"source": "Tempo", "target": "时间"},
{"source": "Hoje", "target": "今天"},
{"source": "Amanhã", "target": "明天"},
{"source": "Amor", "target": "爱"},
{"source": "Família", "target": "家庭"},
{"source": "Amigo", "target": "朋友"},
{"source": "Escola", "target": "学校"},
{"source": "Trabalho", "target": "工作"},
{"source": "Computador", "target": "电脑"},
{"source": "Telefone", "target": "手机"},
{"source": "Carro", "target": "汽车"},
{"source": "Dinheiro", "target": "钱"},
{"source": "Música", "target": "音乐"},
{"source": "Livro", "target": "书"},
{"source": "Água", "target": "水"},
{"source": "Comida", "target": "食物"}
]
}
}

@ -0,0 +1,35 @@
{
"fileName": "dictionary_ru_zh.json",
"fileContent": {
"entries": [
{"source": "Здравствуйте", "target": "你好"},
{"source": "Спасибо", "target": "谢谢"},
{"source": "Извините", "target": "对不起"},
{"source": "До свидания", "target": "再见"},
{"source": "Да", "target": "是"},
{"source": "Нет", "target": "不"},
{"source": "Я", "target": "我"},
{"source": "Ты", "target": "你"},
{"source": "Он", "target": "他"},
{"source": "Она", "target": "她"},
{"source": "Мы", "target": "我们"},
{"source": "Они", "target": "他们"},
{"source": "Время", "target": "时间"},
{"source": "Сегодня", "target": "今天"},
{"source": "Завтра", "target": "明天"},
{"source": "Любовь", "target": "爱"},
{"source": "Семья", "target": "家庭"},
{"source": "Друг", "target": "朋友"},
{"source": "Школа", "target": "学校"},
{"source": "Работа", "target": "工作"},
{"source": "Компьютер", "target": "电脑"},
{"source": "Телефон", "target": "手机"},
{"source": "Машина", "target": "汽车"},
{"source": "Деньги", "target": "钱"},
{"source": "Музыка", "target": "音乐"},
{"source": "Книга", "target": "书"},
{"source": "Вода", "target": "水"},
{"source": "Еда", "target": "食物"}
]
}
}

@ -0,0 +1,72 @@
{
"fileName": "dictionary_zh_de.json",
"fileContent": {
"entries": [
{"source": "你好", "target": "Hallo"},
{"source": "谢谢", "target": "Danke"},
{"source": "对不起", "target": "Entschuldigung"},
{"source": "再见", "target": "Auf Wiedersehen"},
{"source": "是", "target": "Ja"},
{"source": "不", "target": "Nein"},
{"source": "我", "target": "Ich"},
{"source": "你", "target": "Du"},
{"source": "他", "target": "Er"},
{"source": "她", "target": "Sie"},
{"source": "我们", "target": "Wir"},
{"source": "他们", "target": "Sie"},
{"source": "这个", "target": "Dies"},
{"source": "那个", "target": "Das"},
{"source": "什么", "target": "Was"},
{"source": "哪里", "target": "Wo"},
{"source": "为什么", "target": "Warum"},
{"source": "如何", "target": "Wie"},
{"source": "时间", "target": "Zeit"},
{"source": "今天", "target": "Heute"},
{"source": "明天", "target": "Morgen"},
{"source": "昨天", "target": "Gestern"},
{"source": "爱", "target": "Liebe"},
{"source": "家庭", "target": "Familie"},
{"source": "朋友", "target": "Freund"},
{"source": "学校", "target": "Schule"},
{"source": "工作", "target": "Arbeit"},
{"source": "学习", "target": "Lernen"},
{"source": "吃饭", "target": "Essen"},
{"source": "喝水", "target": "Wasser trinken"},
{"source": "睡觉", "target": "Schlafen"},
{"source": "中国", "target": "China"},
{"source": "美国", "target": "Amerika"},
{"source": "日本", "target": "Japan"},
{"source": "韩国", "target": "Korea"},
{"source": "法国", "target": "Frankreich"},
{"source": "德国", "target": "Deutschland"},
{"source": "西班牙", "target": "Spanien"},
{"source": "俄罗斯", "target": "Russland"},
{"source": "苹果", "target": "Apfel"},
{"source": "香蕉", "target": "Banane"},
{"source": "水", "target": "Wasser"},
{"source": "茶", "target": "Tee"},
{"source": "咖啡", "target": "Kaffee"},
{"source": "书", "target": "Buch"},
{"source": "电脑", "target": "Computer"},
{"source": "手机", "target": "Handy"},
{"source": "汽车", "target": "Auto"},
{"source": "房子", "target": "Haus"},
{"source": "钱", "target": "Geld"},
{"source": "音乐", "target": "Musik"},
{"source": "电影", "target": "Film"},
{"source": "大", "target": "Groß"},
{"source": "小", "target": "Klein"},
{"source": "好", "target": "Gut"},
{"source": "坏", "target": "Schlecht"},
{"source": "热", "target": "Heiß"},
{"source": "冷", "target": "Kalt"},
{"source": "新", "target": "Neu"},
{"source": "旧", "target": "Alt"},
{"source": "红色", "target": "Rot"},
{"source": "蓝色", "target": "Blau"},
{"source": "绿色", "target": "Grün"},
{"source": "白色", "target": "Weiß"},
{"source": "黑色", "target": "Schwarz"}
]
}
}

@ -0,0 +1,91 @@
{
"entries": [
{"source": "你好", "target": "Hello"},
{"source": "谢谢", "target": "Thank you"},
{"source": "再见", "target": "Goodbye"},
{"source": "是", "target": "Yes"},
{"source": "不", "target": "No"},
{"source": "我", "target": "I"},
{"source": "你", "target": "You"},
{"source": "他", "target": "He"},
{"source": "她", "target": "She"},
{"source": "我们", "target": "We"},
{"source": "他们", "target": "They"},
{"source": "这个", "target": "This"},
{"source": "那个", "target": "That"},
{"source": "什么", "target": "What"},
{"source": "哪里", "target": "Where"},
{"source": "为什么", "target": "Why"},
{"source": "如何", "target": "How"},
{"source": "时间", "target": "Time"},
{"source": "今天", "target": "Today"},
{"source": "明天", "target": "Tomorrow"},
{"source": "爱", "target": "Love"},
{"source": "家", "target": "Home"},
{"source": "学校", "target": "School"},
{"source": "工作", "target": "Work"},
{"source": "吃饭", "target": "Eat"},
{"source": "喝水", "target": "Drink"},
{"source": "学习", "target": "Study"},
{"source": "朋友", "target": "Friend"},
{"source": "家人", "target": "Family"},
{"source": "中国", "target": "China"},
{"source": "美国", "target": "America"},
{"source": "英国", "target": "England"},
{"source": "日本", "target": "Japan"},
{"source": "韩国", "target": "Korea"},
{"source": "法国", "target": "France"},
{"source": "德国", "target": "Germany"},
{"source": "俄罗斯", "target": "Russia"},
{"source": "苹果", "target": "Apple"},
{"source": "香蕉", "target": "Banana"},
{"source": "水", "target": "Water"},
{"source": "茶", "target": "Tea"},
{"source": "咖啡", "target": "Coffee"},
{"source": "书", "target": "Book"},
{"source": "笔", "target": "Pen"},
{"source": "电脑", "target": "Computer"},
{"source": "手机", "target": "Phone"},
{"source": "汽车", "target": "Car"},
{"source": "房子", "target": "House"},
{"source": "钱", "target": "Money"},
{"source": "音乐", "target": "Music"},
{"source": "电影", "target": "Movie"},
{"source": "游戏", "target": "Game"},
{"source": "运动", "target": "Sports"},
{"source": "健康", "target": "Health"},
{"source": "美丽", "target": "Beautiful"},
{"source": "快乐", "target": "Happy"},
{"source": "悲伤", "target": "Sad"},
{"source": "大", "target": "Big"},
{"source": "小", "target": "Small"},
{"source": "好", "target": "Good"},
{"source": "坏", "target": "Bad"},
{"source": "快", "target": "Fast"},
{"source": "慢", "target": "Slow"},
{"source": "热", "target": "Hot"},
{"source": "冷", "target": "Cold"},
{"source": "新", "target": "New"},
{"source": "旧", "target": "Old"},
{"source": "高", "target": "High"},
{"source": "低", "target": "Low"},
{"source": "长", "target": "Long"},
{"source": "短", "target": "Short"},
{"source": "红色", "target": "Red"},
{"source": "蓝色", "target": "Blue"},
{"source": "绿色", "target": "Green"},
{"source": "黄色", "target": "Yellow"},
{"source": "白色", "target": "White"},
{"source": "黑色", "target": "Black"},
{"source": "一", "target": "One"},
{"source": "二", "target": "Two"},
{"source": "三", "target": "Three"},
{"source": "四", "target": "Four"},
{"source": "五", "target": "Five"},
{"source": "六", "target": "Six"},
{"source": "七", "target": "Seven"},
{"source": "八", "target": "Eight"},
{"source": "九", "target": "Nine"},
{"source": "十", "target": "Ten"}
]
}

@ -0,0 +1,72 @@
{
"fileName": "dictionary_zh_es.json",
"fileContent": {
"entries": [
{"source": "你好", "target": "Hola"},
{"source": "谢谢", "target": "Gracias"},
{"source": "对不起", "target": "Lo siento"},
{"source": "再见", "target": "Adiós"},
{"source": "是", "target": "Sí"},
{"source": "不", "target": "No"},
{"source": "我", "target": "Yo"},
{"source": "你", "target": "Tú"},
{"source": "他", "target": "Él"},
{"source": "她", "target": "Ella"},
{"source": "我们", "target": "Nosotros"},
{"source": "他们", "target": "Ellos"},
{"source": "这个", "target": "Este"},
{"source": "那个", "target": "Ese"},
{"source": "什么", "target": "Qué"},
{"source": "哪里", "target": "Dónde"},
{"source": "为什么", "target": "Por qué"},
{"source": "如何", "target": "Cómo"},
{"source": "时间", "target": "Tiempo"},
{"source": "今天", "target": "Hoy"},
{"source": "明天", "target": "Mañana"},
{"source": "昨天", "target": "Ayer"},
{"source": "爱", "target": "Amor"},
{"source": "家庭", "target": "Familia"},
{"source": "朋友", "target": "Amigo"},
{"source": "学校", "target": "Escuela"},
{"source": "工作", "target": "Trabajo"},
{"source": "学习", "target": "Estudiar"},
{"source": "吃饭", "target": "Comer"},
{"source": "喝水", "target": "Beber agua"},
{"source": "睡觉", "target": "Dormir"},
{"source": "中国", "target": "China"},
{"source": "美国", "target": "Estados Unidos"},
{"source": "日本", "target": "Japón"},
{"source": "韩国", "target": "Corea"},
{"source": "法国", "target": "Francia"},
{"source": "德国", "target": "Alemania"},
{"source": "西班牙", "target": "España"},
{"source": "俄罗斯", "target": "Rusia"},
{"source": "苹果", "target": "Manzana"},
{"source": "香蕉", "target": "Plátano"},
{"source": "水", "target": "Agua"},
{"source": "茶", "target": "Té"},
{"source": "咖啡", "target": "Café"},
{"source": "书", "target": "Libro"},
{"source": "电脑", "target": "Computadora"},
{"source": "手机", "target": "Teléfono"},
{"source": "汽车", "target": "Coche"},
{"source": "房子", "target": "Casa"},
{"source": "钱", "target": "Dinero"},
{"source": "音乐", "target": "Música"},
{"source": "电影", "target": "Película"},
{"source": "大", "target": "Grande"},
{"source": "小", "target": "Pequeño"},
{"source": "好", "target": "Bueno"},
{"source": "坏", "target": "Malo"},
{"source": "热", "target": "Caliente"},
{"source": "冷", "target": "Frío"},
{"source": "新", "target": "Nuevo"},
{"source": "旧", "target": "Viejo"},
{"source": "红色", "target": "Rojo"},
{"source": "蓝色", "target": "Azul"},
{"source": "绿色", "target": "Verde"},
{"source": "白色", "target": "Blanco"},
{"source": "黑色", "target": "Negro"}
]
}
}

@ -0,0 +1,63 @@
{
"entries": [
{"source": "你好", "target": "Bonjour"},
{"source": "谢谢", "target": "Merci"},
{"source": "对不起", "target": "Désolé"},
{"source": "再见", "target": "Au revoir"},
{"source": "是", "target": "Oui"},
{"source": "不", "target": "Non"},
{"source": "我", "target": "Je"},
{"source": "你", "target": "Tu"},
{"source": "他", "target": "Il"},
{"source": "她", "target": "Elle"},
{"source": "我们", "target": "Nous"},
{"source": "他们", "target": "Ils"},
{"source": "这个", "target": "Ceci"},
{"source": "那个", "target": "Cela"},
{"source": "什么", "target": "Quoi"},
{"source": "哪里", "target": "Où"},
{"source": "为什么", "target": "Pourquoi"},
{"source": "如何", "target": "Comment"},
{"source": "时间", "target": "Temps"},
{"source": "今天", "target": "Aujourd'hui"},
{"source": "明天", "target": "Demain"},
{"source": "昨天", "target": "Hier"},
{"source": "爱", "target": "Amour"},
{"source": "家庭", "target": "Famille"},
{"source": "朋友", "target": "Ami"},
{"source": "学校", "target": "École"},
{"source": "工作", "target": "Travail"},
{"source": "吃饭", "target": "Manger"},
{"source": "喝水", "target": "Boire de l'eau"},
{"source": "学习", "target": "Étudier"},
{"source": "中国", "target": "Chine"},
{"source": "法国", "target": "France"},
{"source": "巴黎", "target": "Paris"},
{"source": "北京", "target": "Pékin"},
{"source": "苹果", "target": "Pomme"},
{"source": "香蕉", "target": "Banane"},
{"source": "水", "target": "Eau"},
{"source": "茶", "target": "Thé"},
{"source": "咖啡", "target": "Café"},
{"source": "书", "target": "Livre"},
{"source": "电脑", "target": "Ordinateur"},
{"source": "手机", "target": "Téléphone portable"},
{"source": "汽车", "target": "Voiture"},
{"source": "钱", "target": "Argent"},
{"source": "音乐", "target": "Musique"},
{"source": "电影", "target": "Film"},
{"source": "大", "target": "Grand"},
{"source": "小", "target": "Petit"},
{"source": "好", "target": "Bon"},
{"source": "坏", "target": "Mauvais"},
{"source": "热", "target": "Chaud"},
{"source": "冷", "target": "Froid"},
{"source": "新", "target": "Nouveau"},
{"source": "旧", "target": "Vieux"},
{"source": "红色", "target": "Rouge"},
{"source": "蓝色", "target": "Bleu"},
{"source": "绿色", "target": "Vert"},
{"source": "白色", "target": "Blanc"},
{"source": "黑色", "target": "Noir"}
]
}

@ -0,0 +1,63 @@
{
"entries": [
{"source": "你好", "target": "こんにちは"},
{"source": "谢谢", "target": "ありがとう"},
{"source": "对不起", "target": "すみません"},
{"source": "再见", "target": "さようなら"},
{"source": "是", "target": "はい"},
{"source": "不", "target": "いいえ"},
{"source": "我", "target": "私"},
{"source": "你", "target": "あなた"},
{"source": "他", "target": "彼"},
{"source": "她", "target": "彼女"},
{"source": "我们", "target": "私たち"},
{"source": "他们", "target": "彼ら"},
{"source": "这个", "target": "これ"},
{"source": "那个", "target": "それ"},
{"source": "什么", "target": "何"},
{"source": "哪里", "target": "どこ"},
{"source": "为什么", "target": "なぜ"},
{"source": "如何", "target": "どのように"},
{"source": "时间", "target": "時間"},
{"source": "今天", "target": "今日"},
{"source": "明天", "target": "明日"},
{"source": "昨天", "target": "昨日"},
{"source": "爱", "target": "愛"},
{"source": "家庭", "target": "家族"},
{"source": "朋友", "target": "友達"},
{"source": "学校", "target": "学校"},
{"source": "工作", "target": "仕事"},
{"source": "吃饭", "target": "食事"},
{"source": "喝水", "target": "水を飲む"},
{"source": "学习", "target": "勉強"},
{"source": "中国", "target": "中国"},
{"source": "日本", "target": "日本"},
{"source": "东京", "target": "東京"},
{"source": "北京", "target": "北京"},
{"source": "苹果", "target": "りんご"},
{"source": "香蕉", "target": "バナナ"},
{"source": "水", "target": "水"},
{"source": "茶", "target": "お茶"},
{"source": "咖啡", "target": "コーヒー"},
{"source": "书", "target": "本"},
{"source": "电脑", "target": "コンピューター"},
{"source": "手机", "target": "携帯電話"},
{"source": "汽车", "target": "車"},
{"source": "钱", "target": "お金"},
{"source": "音乐", "target": "音楽"},
{"source": "电影", "target": "映画"},
{"source": "大", "target": "大きい"},
{"source": "小", "target": "小さい"},
{"source": "好", "target": "良い"},
{"source": "坏", "target": "悪い"},
{"source": "热", "target": "熱い"},
{"source": "冷", "target": "冷たい"},
{"source": "新", "target": "新しい"},
{"source": "旧", "target": "古い"},
{"source": "红色", "target": "赤"},
{"source": "蓝色", "target": "青"},
{"source": "绿色", "target": "緑"},
{"source": "白色", "target": "白"},
{"source": "黑色", "target": "黒"}
]
}

@ -0,0 +1,63 @@
{
"entries": [
{"source": "你好", "target": "안녕하세요"},
{"source": "谢谢", "target": "감사합니다"},
{"source": "对不起", "target": "죄송합니다"},
{"source": "再见", "target": "안녕히 가세요"},
{"source": "是", "target": "네"},
{"source": "不", "target": "아니요"},
{"source": "我", "target": "나"},
{"source": "你", "target": "너"},
{"source": "他", "target": "그"},
{"source": "她", "target": "그녀"},
{"source": "我们", "target": "우리"},
{"source": "他们", "target": "그들"},
{"source": "这个", "target": "이것"},
{"source": "那个", "target": "그것"},
{"source": "什么", "target": "무엇"},
{"source": "哪里", "target": "어디"},
{"source": "为什么", "target": "왜"},
{"source": "如何", "target": "어떻게"},
{"source": "时间", "target": "시간"},
{"source": "今天", "target": "오늘"},
{"source": "明天", "target": "내일"},
{"source": "昨天", "target": "어제"},
{"source": "爱", "target": "사랑"},
{"source": "家庭", "target": "가족"},
{"source": "朋友", "target": "친구"},
{"source": "学校", "target": "학교"},
{"source": "工作", "target": "일"},
{"source": "吃饭", "target": "식사"},
{"source": "喝水", "target": "물을 마시다"},
{"source": "学习", "target": "공부"},
{"source": "中国", "target": "중국"},
{"source": "韩国", "target": "한국"},
{"source": "首尔", "target": "서울"},
{"source": "北京", "target": "베이징"},
{"source": "苹果", "target": "사과"},
{"source": "香蕉", "target": "바나나"},
{"source": "水", "target": "물"},
{"source": "茶", "target": "차"},
{"source": "咖啡", "target": "커피"},
{"source": "书", "target": "책"},
{"source": "电脑", "target": "컴퓨터"},
{"source": "手机", "target": "휴대폰"},
{"source": "汽车", "target": "자동차"},
{"source": "钱", "target": "돈"},
{"source": "音乐", "target": "음악"},
{"source": "电影", "target": "영화"},
{"source": "大", "target": "크다"},
{"source": "小", "target": "작다"},
{"source": "好", "target": "좋다"},
{"source": "坏", "target": "나쁘다"},
{"source": "热", "target": "뜨겁다"},
{"source": "冷", "target": "차갑다"},
{"source": "新", "target": "새로운"},
{"source": "旧", "target": "오래된"},
{"source": "红色", "target": "빨간색"},
{"source": "蓝色", "target": "파란색"},
{"source": "绿色", "target": "초록색"},
{"source": "白色", "target": "하얀색"},
{"source": "黑色", "target": "검은색"}
]
}

@ -0,0 +1,72 @@
{
"fileName": "dictionary_zh_ru.json",
"fileContent": {
"entries": [
{"source": "你好", "target": "Здравствуйте"},
{"source": "谢谢", "target": "Спасибо"},
{"source": "对不起", "target": "Извините"},
{"source": "再见", "target": "До свидания"},
{"source": "是", "target": "Да"},
{"source": "不", "target": "Нет"},
{"source": "我", "target": "Я"},
{"source": "你", "target": "Ты"},
{"source": "他", "target": "Он"},
{"source": "她", "target": "Она"},
{"source": "我们", "target": "Мы"},
{"source": "他们", "target": "Они"},
{"source": "这个", "target": "Это"},
{"source": "那个", "target": "То"},
{"source": "什么", "target": "Что"},
{"source": "哪里", "target": "Где"},
{"source": "为什么", "target": "Почему"},
{"source": "如何", "target": "Как"},
{"source": "时间", "target": "Время"},
{"source": "今天", "target": "Сегодня"},
{"source": "明天", "target": "Завтра"},
{"source": "昨天", "target": "Вчера"},
{"source": "爱", "target": "Любовь"},
{"source": "家庭", "target": "Семья"},
{"source": "朋友", "target": "Друг"},
{"source": "学校", "target": "Школа"},
{"source": "工作", "target": "Работа"},
{"source": "学习", "target": "Учиться"},
{"source": "吃饭", "target": "Есть"},
{"source": "喝水", "target": "Пить воду"},
{"source": "睡觉", "target": "Спать"},
{"source": "中国", "target": "Китай"},
{"source": "美国", "target": "Америка"},
{"source": "日本", "target": "Япония"},
{"source": "韩国", "target": "Корея"},
{"source": "法国", "target": "Франция"},
{"source": "德国", "target": "Германия"},
{"source": "西班牙", "target": "Испания"},
{"source": "俄罗斯", "target": "Россия"},
{"source": "苹果", "target": "Яблоко"},
{"source": "香蕉", "target": "Банан"},
{"source": "水", "target": "Вода"},
{"source": "茶", "target": "Чай"},
{"source": "咖啡", "target": "Кофе"},
{"source": "书", "target": "Книга"},
{"source": "电脑", "target": "Компьютер"},
{"source": "手机", "target": "Телефон"},
{"source": "汽车", "target": "Машина"},
{"source": "房子", "target": "Дом"},
{"source": "钱", "target": "Деньги"},
{"source": "音乐", "target": "Музыка"},
{"source": "电影", "target": "Фильм"},
{"source": "大", "target": "Большой"},
{"source": "小", "target": "Маленький"},
{"source": "好", "target": "Хороший"},
{"source": "坏", "target": "Плохой"},
{"source": "热", "target": "Горячий"},
{"source": "冷", "target": "Холодный"},
{"source": "新", "target": "Новый"},
{"source": "旧", "target": "Старый"},
{"source": "红色", "target": "Красный"},
{"source": "蓝色", "target": "Синий"},
{"source": "绿色", "target": "Зеленый"},
{"source": "白色", "target": "Белый"},
{"source": "黑色", "target": "Черный"}
]
}
}

@ -0,0 +1,354 @@
package com.translation.activity;
import android.app.Dialog;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.translation.app.R;
import com.translation.service.AuthService;
public class LoginActivity extends AppCompatActivity {
private static final String TAG = "LoginActivity";
private EditText phoneEditText;
private EditText passwordEditText;
private Button loginButton;
private TextView registerLink;
private TextView agreementTextView;
private CheckBox rememberPasswordCheckbox;
private AuthService authService;
private Dialog registerDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate");
setContentView(R.layout.activity_login);
authService = new AuthService(this);
initializeViews();
setupEventListeners();
// 检查是否已登录
if (authService.isLoggedIn()) {
Log.d(TAG, "用户已登录,自动跳转到主页面");
openMainTranslationActivity();
} else {
// 自动填充上次登录的手机号
autoFillLastLoginInfo();
}
}
private void initializeViews() {
Log.d(TAG, "initializeViews");
phoneEditText = findViewById(R.id.phone_edit_text);
passwordEditText = findViewById(R.id.password_edit_text);
loginButton = findViewById(R.id.login_button);
registerLink = findViewById(R.id.register_link);
agreementTextView = findViewById(R.id.agreement_text);
rememberPasswordCheckbox = findViewById(R.id.remember_password_checkbox);
// 设置记住密码复选框的初始状态
rememberPasswordCheckbox.setChecked(authService.getRememberPassword());
}
private void setupEventListeners() {
Log.d(TAG, "setupEventListeners");
loginButton.setOnClickListener(v -> {
Log.d(TAG, "登录按钮点击");
handleLogin();
});
registerLink.setOnClickListener(v -> {
Log.d(TAG, "注册链接点击");
showRegisterDialog();
});
agreementTextView.setOnClickListener(v -> {
Toast.makeText(this, "显示用户协议", Toast.LENGTH_SHORT).show();
});
// 记住密码复选框监听
rememberPasswordCheckbox.setOnCheckedChangeListener((buttonView, isChecked) -> {
authService.setRememberPassword(isChecked);
Log.d(TAG, "记住密码设置: " + isChecked);
});
// 手机号输入监听,用于自动填充密码
phoneEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
@Override
public void afterTextChanged(Editable s) {
String phoneNumber = s.toString().trim();
if (phoneNumber.length() == 11 && authService.userExists(phoneNumber)) {
// 自动填充已保存的密码
String savedPassword = authService.getSavedPassword(phoneNumber);
if (savedPassword != null) {
passwordEditText.setText(savedPassword);
Toast.makeText(LoginActivity.this, "已自动填充保存的密码", Toast.LENGTH_SHORT).show();
}
}
}
});
}
/**
*
*/
private void showRegisterDialog() {
registerDialog = new Dialog(this);
registerDialog.setContentView(R.layout.dialog_register);
registerDialog.setCancelable(true);
registerDialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent);
// 初始化对话框中的视图
EditText registerPhoneEditText = registerDialog.findViewById(R.id.register_phone_edit_text);
EditText registerPasswordEditText = registerDialog.findViewById(R.id.register_password_edit_text);
EditText registerConfirmPasswordEditText = registerDialog.findViewById(R.id.register_confirm_password_edit_text);
Button cancelButton = registerDialog.findViewById(R.id.cancel_button);
Button confirmRegisterButton = registerDialog.findViewById(R.id.confirm_register_button);
TextView registerAgreementText = registerDialog.findViewById(R.id.register_agreement_text);
// 填充当前输入的手机号
String currentPhone = phoneEditText.getText().toString().trim();
if (!TextUtils.isEmpty(currentPhone)) {
registerPhoneEditText.setText(currentPhone);
}
// 取消按钮
cancelButton.setOnClickListener(v -> {
registerDialog.dismiss();
});
// 确认注册按钮
confirmRegisterButton.setOnClickListener(v -> {
handleRegister(
registerPhoneEditText.getText().toString().trim(),
registerPasswordEditText.getText().toString().trim(),
registerConfirmPasswordEditText.getText().toString().trim()
);
});
// 协议文本点击
registerAgreementText.setOnClickListener(v -> {
Toast.makeText(this, "显示用户协议", Toast.LENGTH_SHORT).show();
});
registerDialog.show();
}
/**
*
*/
private void autoFillLastLoginInfo() {
String lastLoginPhone = authService.getLastLoginPhone();
if (!TextUtils.isEmpty(lastLoginPhone)) {
phoneEditText.setText(lastLoginPhone);
// 如果用户存在,自动填充密码
if (authService.userExists(lastLoginPhone)) {
String savedPassword = authService.getSavedPassword(lastLoginPhone);
if (savedPassword != null) {
passwordEditText.setText(savedPassword);
}
}
}
}
private void handleLogin() {
Log.d(TAG, "=== handleLogin 开始 ===");
String phoneNumber = phoneEditText.getText().toString().trim();
String password = passwordEditText.getText().toString().trim();
Log.d(TAG, "手机号: " + phoneNumber + ", 密码: " + password);
// 输入验证
if (TextUtils.isEmpty(phoneNumber)) {
Log.d(TAG, "手机号为空");
Toast.makeText(this, "请输入手机号", Toast.LENGTH_SHORT).show();
return;
}
if (phoneNumber.length() != 11) {
Log.d(TAG, "手机号格式错误");
Toast.makeText(this, "请输入正确的11位手机号", Toast.LENGTH_SHORT).show();
return;
}
if (TextUtils.isEmpty(password)) {
Log.d(TAG, "密码为空");
Toast.makeText(this, "请输入密码", Toast.LENGTH_SHORT).show();
return;
}
if (password.length() < 6) {
Log.d(TAG, "密码长度不足");
Toast.makeText(this, "密码长度至少6位", Toast.LENGTH_SHORT).show();
return;
}
// 检查用户是否存在
if (!authService.userExists(phoneNumber)) {
Log.d(TAG, "用户未注册");
Toast.makeText(this, "该手机号未注册,请先注册", Toast.LENGTH_SHORT).show();
return;
}
Log.d(TAG, "准备调用 authService.login");
loginButton.setEnabled(false);
loginButton.setText("登录中...");
authService.login(phoneNumber, password, new AuthService.AuthCallback() {
@Override
public void onSuccess() {
Log.d(TAG, "=== AuthService.onSuccess 回调 ===");
runOnUiThread(() -> {
Log.d(TAG, "在UI线程中执行");
Toast.makeText(LoginActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
openMainTranslationActivity();
});
}
@Override
public void onError(String errorMessage) {
Log.e(TAG, "=== AuthService.onError: " + errorMessage);
runOnUiThread(() -> {
Toast.makeText(LoginActivity.this, errorMessage, Toast.LENGTH_SHORT).show();
loginButton.setEnabled(true);
loginButton.setText("登录");
});
}
});
Log.d(TAG, "=== handleLogin 结束 ===");
}
private void handleRegister(String phoneNumber, String password, String confirmPassword) {
Log.d(TAG, "=== handleRegister 开始 ===");
Log.d(TAG, "注册信息 - 手机号: " + phoneNumber + ", 密码: " + password + ", 确认密码: " + confirmPassword);
// 输入验证
if (TextUtils.isEmpty(phoneNumber)) {
Log.d(TAG, "手机号为空");
Toast.makeText(this, "请输入手机号", Toast.LENGTH_SHORT).show();
return;
}
if (phoneNumber.length() != 11) {
Log.d(TAG, "手机号格式错误");
Toast.makeText(this, "请输入正确的11位手机号", Toast.LENGTH_SHORT).show();
return;
}
if (TextUtils.isEmpty(password)) {
Log.d(TAG, "密码为空");
Toast.makeText(this, "请输入密码", Toast.LENGTH_SHORT).show();
return;
}
if (password.length() < 6) {
Log.d(TAG, "密码长度不足");
Toast.makeText(this, "密码长度至少6位", Toast.LENGTH_SHORT).show();
return;
}
if (!password.equals(confirmPassword)) {
Log.d(TAG, "密码不一致");
Toast.makeText(this, "两次输入的密码不一致", Toast.LENGTH_SHORT).show();
return;
}
// 检查用户是否已存在
if (authService.userExists(phoneNumber)) {
Log.d(TAG, "用户已存在");
Toast.makeText(this, "该手机号已注册,请直接登录", Toast.LENGTH_SHORT).show();
return;
}
Log.d(TAG, "准备调用 authService.register");
Button confirmButton = registerDialog.findViewById(R.id.confirm_register_button);
confirmButton.setEnabled(false);
confirmButton.setText("注册中...");
authService.register(phoneNumber, password, new AuthService.AuthCallback() {
@Override
public void onSuccess() {
Log.d(TAG, "=== AuthService.onSuccess 回调 ===");
runOnUiThread(() -> {
Log.d(TAG, "在UI线程中执行");
Toast.makeText(LoginActivity.this, "注册成功", Toast.LENGTH_SHORT).show();
// 自动填充注册的信息到登录表单
phoneEditText.setText(phoneNumber);
passwordEditText.setText(password);
// 关闭对话框
if (registerDialog != null && registerDialog.isShowing()) {
registerDialog.dismiss();
}
// 提示用户登录
Toast.makeText(LoginActivity.this, "注册成功,请点击登录", Toast.LENGTH_SHORT).show();
});
}
@Override
public void onError(String errorMessage) {
Log.e(TAG, "=== AuthService.onError: " + errorMessage);
runOnUiThread(() -> {
Toast.makeText(LoginActivity.this, errorMessage, Toast.LENGTH_SHORT).show();
if (registerDialog != null) {
Button confirmButton = registerDialog.findViewById(R.id.confirm_register_button);
confirmButton.setEnabled(true);
confirmButton.setText("注册");
}
});
}
});
Log.d(TAG, "=== handleRegister 结束 ===");
}
private void openMainTranslationActivity() {
Log.d(TAG, "=== openMainTranslationActivity ===");
try {
Log.d(TAG, "创建Intent");
Intent intent = new Intent(this, MainTranslationActivity.class);
Log.d(TAG, "启动Activity");
startActivity(intent);
Log.d(TAG, "结束当前Activity");
finish();
Log.d(TAG, "跳转完成");
} catch (Exception e) {
Log.e(TAG, "跳转异常: " + e.getMessage(), e);
Toast.makeText(this, "跳转失败: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (registerDialog != null && registerDialog.isShowing()) {
registerDialog.dismiss();
}
}
}

@ -0,0 +1,250 @@
package com.translation.activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.widget.CompoundButton;
import android.widget.Switch;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import com.translation.app.R;
import com.translation.app.AppState;
import com.translation.model.OfflineTranslationModel;
import android.widget.Toast;
import android.util.Log;
public class SettingsActivity extends AppCompatActivity {
private static final String TAG = "SettingsActivity";
private Switch offlineModeSwitch;
private Switch autoCopySwitch;
private Switch voiceInputSwitch;
private AppState appState;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
appState = AppState.getInstance(this);
initializeViews();
setupEventListeners();
}
private void initializeViews() {
// 初始化开关控件
offlineModeSwitch = findViewById(R.id.offline_mode_switch);
autoCopySwitch = findViewById(R.id.auto_copy_switch);
voiceInputSwitch = findViewById(R.id.voice_input_switch);
// 设置初始状态
offlineModeSwitch.setChecked(!appState.isOnlineMode());
autoCopySwitch.setChecked(appState.isAutoCopyEnabled());
voiceInputSwitch.setChecked(appState.isVoiceInputEnabled());
// 设置返回按钮
findViewById(R.id.back_button).setOnClickListener(v -> onBackPressed());
// 设置其他选项点击事件与XML布局完全对应
findViewById(R.id.export_data_item).setOnClickListener(v -> exportTranslationData());
findViewById(R.id.about_item).setOnClickListener(v -> showAboutDialog());
findViewById(R.id.privacy_item).setOnClickListener(v -> showPrivacyPolicy());
findViewById(R.id.user_agreement_item).setOnClickListener(v -> showUserAgreement());
}
private void showModeChangeDialog(boolean isOnlineMode) {
String message;
if (isOnlineMode) {
message = "已切换到在线模式,可以使用更多功能和更准确的翻译";
} else {
OfflineTranslationModel offlineModel = OfflineTranslationModel.getInstance(this);
if (offlineModel.isMLKitAvailable()) {
message = "已切换到离线模式,使用华为 ML Kit 进行翻译(无需网络)";
} else {
message = "已切换到离线模式,使用基础词典翻译(无需网络)";
}
}
new AlertDialog.Builder(this)
.setTitle("模式切换")
.setMessage(message)
.setPositiveButton("确定", null)
.show();
}
/**
*
*/
private void exportTranslationData() {
// 检查是否有翻译记录
com.translation.service.HistoryService historyService = new com.translation.service.HistoryService(this);
int recordCount = historyService.getRecordCount();
if (recordCount == 0) {
showToast("暂无翻译记录可导出");
return;
}
// 显示确认对话框直接导出TXT格式
new AlertDialog.Builder(this)
.setTitle("导出翻译记录数据")
.setMessage("当前共有 " + recordCount + " 条翻译记录确定要导出为TXT格式吗")
.setPositiveButton("导出", (dialog, which) -> {
// 显示导出进度
showToast("正在导出数据,请稍候...");
new Thread(() -> {
boolean success = historyService.exportHistory("TXT");
runOnUiThread(() -> {
if (success) {
showExportSuccessDialog(recordCount);
} else {
showToast("导出失败,请检查存储权限或存储空间");
}
});
}).start();
})
.setNegativeButton("取消", null)
.show();
}
/**
*
*/
private void showExportSuccessDialog(int recordCount) {
String message = String.format("成功导出 %d 条翻译记录\n\n文件保存位置: \nDocuments/TranslationHistory/", recordCount);
new AlertDialog.Builder(this)
.setTitle("导出成功")
.setMessage(message)
.setPositiveButton("确定", null)
.setNeutralButton("查看文件", (dialog, which) -> {
// 打开文件管理器查看导出的文件
openFileManager();
})
.show();
}
/**
*
*/
private void openFileManager() {
try {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivity(Intent.createChooser(intent, "选择文件管理器"));
} catch (Exception e) {
showToast("无法打开文件管理器");
}
}
private void showAboutDialog() {
new AlertDialog.Builder(this)
.setTitle("关于智能翻译应用")
.setMessage("智能翻译应用\n\n" +
"版本: 1.0.0\n" +
"开发团队: Translation Tech Inc.\n\n" +
"功能特性:\n" +
"• 多语言在线/离线翻译\n" +
"• 语音输入翻译\n" +
"• ML Kit 离线翻译支持\n" +
"• 历史记录管理\n" +
"• 标签分类系统\n" +
"• 翻译记录数据导出\n\n" +
"技术支持: support@translation.com")
.setPositiveButton("确定", null)
.show();
}
private void showPrivacyPolicy() {
new AlertDialog.Builder(this)
.setTitle("隐私政策")
.setMessage("隐私政策\n\n" +
"1. 数据收集\n" +
"我们仅收集必要的翻译文本数据以提供翻译服务。\n\n" +
"2. 数据使用\n" +
"您的数据仅用于翻译处理,不会被用于其他目的。\n\n" +
"3. 数据存储\n" +
"翻译历史仅存储在本地设备上。\n\n" +
"4. 数据共享\n" +
"我们不会与第三方共享您的个人数据。\n\n" +
"5. 数据导出\n" +
"您可以随时导出您的翻译记录数据。")
.setPositiveButton("同意", null)
.show();
}
private void showUserAgreement() {
new AlertDialog.Builder(this)
.setTitle("用户协议")
.setMessage("用户协议\n\n" +
"1. 服务说明\n" +
"本应用提供多语言翻译服务,支持在线和离线模式。\n\n" +
"2. 使用规则\n" +
"用户应遵守相关法律法规,不得使用本应用进行违法活动。\n\n" +
"3. 免责声明\n" +
"翻译结果仅供参考不保证100%准确。\n\n" +
"4. 服务变更\n" +
"我们保留修改或终止服务的权利。\n\n" +
"5. 数据管理\n" +
"用户拥有对自己翻译数据的完全控制权。")
.setPositiveButton("同意", null)
.show();
}
private void showToast(String message) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
@Override
public void onBackPressed() {
super.onBackPressed();
// 添加返回动画
overridePendingTransition(R.anim.slide_in_left, R.anim.slide_out_right);
}
private void setupEventListeners() {
offlineModeSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
// 注意:离线模式开关开启时,表示使用离线模式
boolean isOnlineMode = !isChecked;
// 立即更新状态
appState.setOnlineMode(isOnlineMode);
// 发送广播通知模式变更
Intent intent = new Intent("MODE_CHANGED");
intent.putExtra("isOnlineMode", isOnlineMode);
sendBroadcast(intent);
// 如果切换到离线模式,自动启用 ML Kit如果可用
if (!isOnlineMode) {
OfflineTranslationModel offlineModel = OfflineTranslationModel.getInstance(this);
if (offlineModel.isMLKitAvailable()) {
offlineModel.setUseMLKitAsPrimary(true);
Toast.makeText(this, "已启用 ML Kit 离线翻译", Toast.LENGTH_SHORT).show();
}
}
showModeChangeDialog(isOnlineMode);
});
autoCopySwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
// 立即更新自动复制设置
appState.setAutoCopyEnabled(isChecked);
String message = isChecked ?
"已开启自动复制功能,翻译完成后将自动复制结果" :
"已关闭自动复制功能";
showToast(message);
Log.d(TAG, "自动复制功能: " + (isChecked ? "开启" : "关闭"));
});
voiceInputSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
appState.setVoiceInputEnabled(isChecked);
showToast(isChecked ? "已开启语音输入" : "已关闭语音输入");
});
}
}

@ -0,0 +1,175 @@
package com.translation.activity;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.translation.app.R;
import com.translation.adapter.TagAdapter;
import com.translation.app.AppState;
import com.translation.model.Tag;
import com.translation.service.TagService;
import com.translation.util.StringUtil;
import android.content.Intent;
public class TagManagementActivity extends AppCompatActivity {
private RecyclerView tagRecyclerView;
private Button newTagButton;
private TagService tagService;
private AppState appState;
private TagAdapter tagAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tags);
tagService = new TagService(this);
appState = AppState.getInstance(this);
initializeViews();
setupRecyclerView();
setupEventListeners();
}
private void initializeViews() {
tagRecyclerView = findViewById(R.id.tag_recycler_view);
newTagButton = findViewById(R.id.new_tag_button);
// 设置返回按钮
findViewById(R.id.back_button).setOnClickListener(v -> onBackPressed());
}
private void setupRecyclerView() {
// 传入 tagService
tagAdapter = new TagAdapter(appState.getTags(), tagService);
tagRecyclerView.setLayoutManager(new LinearLayoutManager(this));
tagRecyclerView.setAdapter(tagAdapter);
// 设置标签点击监听器
tagAdapter.setOnTagClickListener(new TagAdapter.OnTagClickListener() {
@Override
public void onTagClick(Tag tag) {
openTagRecordsActivity(tag);
}
});
// 设置标签操作监听器
tagAdapter.setOnTagOperationListener(new TagAdapter.OnTagOperationListener() {
@Override
public void onEditTag(Tag tag) {
showEditTagDialog(tag);
}
@Override
public void onDeleteTag(Tag tag) {
showDeleteTagDialog(tag);
}
});
}
/**
*
*/
private void openTagRecordsActivity(Tag tag) {
Intent intent = new Intent(this, TagRecordsActivity.class);
intent.putExtra("tag_id", tag.getId());
intent.putExtra("tag_name", tag.getName());
startActivity(intent);
// 添加过渡动画
overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_left);
}
private void setupEventListeners() {
newTagButton.setOnClickListener(v -> showNewTagDialog());
}
private void showNewTagDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("新建标签");
View dialogView = getLayoutInflater().inflate(R.layout.dialog_edit_tag, null);
builder.setView(dialogView);
androidx.appcompat.widget.AppCompatEditText tagNameEditText =
dialogView.findViewById(R.id.tag_name_edit_text);
builder.setPositiveButton("创建", (dialog, which) -> {
String tagName = tagNameEditText.getText().toString().trim();
if (StringUtil.isEmpty(tagName)) {
Toast.makeText(this, "请输入标签名称", Toast.LENGTH_SHORT).show();
return;
}
if (tagService.createTag(tagName)) {
tagAdapter.updateData(appState.getTags());
Toast.makeText(this, "标签创建成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "标签已存在或创建失败", Toast.LENGTH_SHORT).show();
}
});
builder.setNegativeButton("取消", null);
AlertDialog dialog = builder.create();
dialog.show();
}
private void showEditTagDialog(Tag tag) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("编辑标签");
View dialogView = getLayoutInflater().inflate(R.layout.dialog_edit_tag, null);
builder.setView(dialogView);
androidx.appcompat.widget.AppCompatEditText tagNameEditText =
dialogView.findViewById(R.id.tag_name_edit_text);
tagNameEditText.setText(tag.getName());
builder.setPositiveButton("保存", (dialog, which) -> {
String newName = tagNameEditText.getText().toString().trim();
if (StringUtil.isEmpty(newName)) {
Toast.makeText(this, "请输入标签名称", Toast.LENGTH_SHORT).show();
return;
}
if (tagService.updateTag(tag.getId(), newName)) {
tagAdapter.updateData(appState.getTags());
Toast.makeText(this, "标签更新成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "标签更新失败", Toast.LENGTH_SHORT).show();
}
});
builder.setNegativeButton("取消", null);
AlertDialog dialog = builder.create();
dialog.show();
}
private void showDeleteTagDialog(Tag tag) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("删除标签");
builder.setMessage("确定要删除标签 \"" + tag.getName() + "\" 吗?");
builder.setPositiveButton("删除", (dialog, which) -> {
if (tagService.deleteTag(tag.getId())) {
tagAdapter.updateData(appState.getTags());
Toast.makeText(this, "标签删除成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "标签删除失败", Toast.LENGTH_SHORT).show();
}
});
builder.setNegativeButton("取消", null);
AlertDialog dialog = builder.create();
dialog.show();
}
}

@ -0,0 +1,119 @@
package com.translation.activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.translation.app.R;
import com.translation.adapter.HistoryAdapter;
import com.translation.model.TranslationRecord;
import com.translation.service.HistoryService;
import com.translation.service.TagService;
import java.util.List;
public class TagRecordsActivity extends AppCompatActivity {
private RecyclerView recordsRecyclerView;
private TextView titleTextView;
private TextView emptyTextView;
private HistoryService historyService;
private TagService tagService;
private HistoryAdapter historyAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tag_records);
historyService = new HistoryService(this);
tagService = new TagService(this);
initializeViews();
loadTagRecords();
}
private void initializeViews() {
// 返回按钮
Button backButton = findViewById(R.id.back_button);
backButton.setOnClickListener(v -> onBackPressed());
titleTextView = findViewById(R.id.title_text_view);
recordsRecyclerView = findViewById(R.id.records_recycler_view);
emptyTextView = findViewById(R.id.empty_text_view);
// 设置布局管理器
recordsRecyclerView.setLayoutManager(new LinearLayoutManager(this));
}
private void loadTagRecords() {
// 获取传递过来的标签信息
int tagId = getIntent().getIntExtra("tag_id", -1);
String tagName = getIntent().getStringExtra("tag_name");
if (tagId == -1 || tagName == null) {
finish();
return;
}
// 设置标题
titleTextView.setText("标签: " + tagName + " (" + getRecordsCount(tagName) + "条记录)");
// 获取该标签对应的翻译记录
List<TranslationRecord> records = historyService.getRecordsByTag(tagName);
if (records.isEmpty()) {
showEmptyState(tagName);
} else {
showRecords(records);
}
}
private int getRecordsCount(String tagName) {
List<TranslationRecord> records = historyService.getRecordsByTag(tagName);
return records != null ? records.size() : 0;
}
private void showRecords(List<TranslationRecord> records) {
emptyTextView.setVisibility(View.GONE);
recordsRecyclerView.setVisibility(View.VISIBLE);
historyAdapter = new HistoryAdapter(records);
recordsRecyclerView.setAdapter(historyAdapter);
// 设置点击监听器(查看详情)
historyAdapter.setOnItemClickListener(new HistoryAdapter.OnItemClickListener() {
@Override
public void onItemClick(TranslationRecord record) {
showRecordDetail(record);
}
@Override
public void onItemLongClick(TranslationRecord record) {
// 在标签记录界面不启用批量模式
}
});
}
private void showEmptyState(String tagName) {
recordsRecyclerView.setVisibility(View.GONE);
emptyTextView.setVisibility(View.VISIBLE);
emptyTextView.setText("标签 \"" + tagName + "\" 下暂无翻译记录");
}
/**
*
*/
private void showRecordDetail(TranslationRecord record) {
// 复用 HistoryActivity 中的方法
HistoryActivity historyActivity = new HistoryActivity();
historyActivity.showRecordDetailDialog(this, record);
}
@Override
public void onBackPressed() {
super.onBackPressed();
overridePendingTransition(R.anim.slide_in_left, R.anim.slide_out_right);
}
}

@ -0,0 +1,17 @@
package com.translation.activity;
import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
public class TestActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 不使用布局文件,直接创建视图
TextView textView = new TextView(this);
textView.setText("测试页面 - R.java 应该已经生成");
setContentView(textView);
}
}

@ -0,0 +1,89 @@
package com.translation.adapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.translation.app.R;
import com.translation.model.GrammarExtension;
import java.util.List;
public class GrammarExtensionAdapter extends RecyclerView.Adapter<GrammarExtensionAdapter.ViewHolder> {
private List<GrammarExtension> extensions;
private OnExtensionClickListener listener;
public interface OnExtensionClickListener {
void onApplyExtension(GrammarExtension extension);
void onExtensionClicked(GrammarExtension extension);
}
public GrammarExtensionAdapter(List<GrammarExtension> extensions, OnExtensionClickListener listener) {
this.extensions = extensions;
this.listener = listener;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_grammar_extension, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
GrammarExtension extension = extensions.get(position);
holder.originalText.setText(extension.getOriginalText());
holder.extendedText.setText(extension.getExtendedText());
holder.extensionTypeText.setText(extension.getExtensionType());
holder.explanationText.setText(extension.getExplanation());
// 设置点击事件
holder.applyButton.setOnClickListener(v -> {
if (listener != null) {
listener.onApplyExtension(extension);
}
});
holder.itemView.setOnClickListener(v -> {
if (listener != null) {
listener.onExtensionClicked(extension);
}
});
}
@Override
public int getItemCount() {
return extensions.size();
}
public void updateExtensions(List<GrammarExtension> newExtensions) {
this.extensions = newExtensions;
notifyDataSetChanged();
}
static class ViewHolder extends RecyclerView.ViewHolder {
TextView originalText;
TextView extendedText;
TextView extensionTypeText;
TextView explanationText;
Button applyButton;
public ViewHolder(@NonNull View itemView) {
super(itemView);
originalText = itemView.findViewById(R.id.original_text);
extendedText = itemView.findViewById(R.id.extended_text);
extensionTypeText = itemView.findViewById(R.id.extension_type_text);
explanationText = itemView.findViewById(R.id.explanation_text);
applyButton = itemView.findViewById(R.id.apply_extension_button);
}
}
}

@ -0,0 +1,92 @@
package com.translation.adapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.translation.app.R;
import com.translation.model.GrammarSuggestion;
import java.util.List;
public class GrammarSuggestionAdapter extends RecyclerView.Adapter<GrammarSuggestionAdapter.ViewHolder> {
private List<GrammarSuggestion> suggestions;
private OnSuggestionClickListener listener;
public interface OnSuggestionClickListener {
void onApplySuggestion(GrammarSuggestion suggestion);
void onSuggestionClicked(GrammarSuggestion suggestion);
}
public GrammarSuggestionAdapter(List<GrammarSuggestion> suggestions, OnSuggestionClickListener listener) {
this.suggestions = suggestions;
this.listener = listener;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_grammar_suggestion, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
GrammarSuggestion suggestion = suggestions.get(position);
holder.originalText.setText(suggestion.getOriginalText());
holder.suggestedText.setText(suggestion.getSuggestedText());
holder.explanationText.setText(suggestion.getExplanation());
holder.categoryTag.setText(suggestion.getCategory());
holder.confidenceText.setText(String.format("%d%%匹配", (int)(suggestion.getConfidence() * 100)));
// 设置点击事件
holder.applyButton.setOnClickListener(v -> {
if (listener != null) {
listener.onApplySuggestion(suggestion);
}
});
holder.itemView.setOnClickListener(v -> {
if (listener != null) {
listener.onSuggestionClicked(suggestion);
}
});
}
@Override
public int getItemCount() {
return suggestions.size();
}
public void updateSuggestions(List<GrammarSuggestion> newSuggestions) {
this.suggestions = newSuggestions;
notifyDataSetChanged();
}
static class ViewHolder extends RecyclerView.ViewHolder {
TextView originalText;
TextView suggestedText;
TextView explanationText;
TextView categoryTag;
TextView confidenceText;
Button applyButton;
public ViewHolder(@NonNull View itemView) {
super(itemView);
originalText = itemView.findViewById(R.id.original_text);
suggestedText = itemView.findViewById(R.id.suggested_text);
explanationText = itemView.findViewById(R.id.explanation_text);
categoryTag = itemView.findViewById(R.id.category_tag);
confidenceText = itemView.findViewById(R.id.confidence_text);
applyButton = itemView.findViewById(R.id.apply_suggestion_button);
}
}
}

@ -0,0 +1,177 @@
package com.translation.adapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.translation.app.R;
import com.translation.model.TranslationRecord;
import java.util.ArrayList;
import java.util.List;
public class HistoryAdapter extends RecyclerView.Adapter<HistoryAdapter.ViewHolder> {
private List<TranslationRecord> records;
private List<Integer> selectedIds;
private boolean isBatchMode;
private OnItemClickListener itemClickListener;
private SelectionListener selectionListener;
public HistoryAdapter(List<TranslationRecord> records) {
this.records = records != null ? records : new ArrayList<>();
this.selectedIds = new ArrayList<>();
this.isBatchMode = false;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_history, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
TranslationRecord record = records.get(position);
holder.sourceText.setText(record.getSourceText());
holder.targetText.setText(record.getTargetText());
holder.languages.setText(record.getSourceLang() + " → " + record.getTargetLang());
holder.timestamp.setText(record.getTimestamp());
// 批量模式处理
if (isBatchMode) {
holder.checkBox.setVisibility(View.VISIBLE);
holder.checkBox.setChecked(selectedIds.contains(record.getId()));
} else {
holder.checkBox.setVisibility(View.GONE);
}
// 点击事件
holder.itemView.setOnClickListener(v -> {
if (isBatchMode) {
toggleSelection(record.getId());
notifyItemChanged(position);
} else if (itemClickListener != null) {
itemClickListener.onItemClick(record);
}
});
holder.itemView.setOnLongClickListener(v -> {
if (!isBatchMode && itemClickListener != null) {
itemClickListener.onItemLongClick(record);
return true;
}
return false;
});
// 复选框点击事件
holder.checkBox.setOnClickListener(v -> {
toggleSelection(record.getId());
notifyItemChanged(position);
});
}
@Override
public int getItemCount() {
return records.size();
}
public void setBatchMode(boolean batchMode) {
isBatchMode = batchMode;
if (!batchMode) {
selectedIds.clear();
notifySelectionChanged();
}
notifyDataSetChanged();
}
public void selectAll() {
selectedIds.clear();
for (TranslationRecord record : records) {
selectedIds.add(record.getId());
}
notifySelectionChanged();
notifyDataSetChanged();
}
public void clearSelection() {
selectedIds.clear();
notifySelectionChanged();
notifyDataSetChanged();
}
public List<Integer> getSelectedRecordIds() {
return new ArrayList<>(selectedIds);
}
public int getSelectedCount() {
return selectedIds.size();
}
public void toggleSelection(int recordId) {
if (selectedIds.contains(recordId)) {
selectedIds.remove(Integer.valueOf(recordId));
} else {
selectedIds.add(recordId);
}
notifySelectionChanged();
}
private void notifySelectionChanged() {
if (selectionListener != null) {
selectionListener.onSelectionChanged(selectedIds.size());
}
}
public void updateData(List<TranslationRecord> newRecords) {
this.records = newRecords != null ? newRecords : new ArrayList<>();
selectedIds.clear();
notifySelectionChanged();
notifyDataSetChanged();
}
public void setOnItemClickListener(OnItemClickListener listener) {
this.itemClickListener = listener;
}
public void setSelectionListener(SelectionListener listener) {
this.selectionListener = listener;
}
public interface OnItemClickListener {
void onItemClick(TranslationRecord record);
void onItemLongClick(TranslationRecord record);
}
public interface SelectionListener {
void onSelectionChanged(int selectedCount);
}
static class ViewHolder extends RecyclerView.ViewHolder {
CheckBox checkBox;
TextView sourceText;
TextView targetText;
TextView languages;
TextView timestamp;
ViewHolder(View itemView) {
super(itemView);
checkBox = itemView.findViewById(R.id.checkbox);
sourceText = itemView.findViewById(R.id.source_text);
targetText = itemView.findViewById(R.id.target_text);
languages = itemView.findViewById(R.id.languages);
timestamp = itemView.findViewById(R.id.timestamp);
}
}
/**
*
*/
public List<TranslationRecord> getCurrentList() {
return records;
}
}

@ -0,0 +1,107 @@
package com.translation.adapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.translation.app.R;
import com.translation.model.Tag;
import com.translation.service.TagService;
import java.util.ArrayList;
import java.util.List;
public class TagAdapter extends RecyclerView.Adapter<TagAdapter.ViewHolder> {
private List<Tag> tags;
private OnTagOperationListener operationListener;
private OnTagClickListener tagClickListener;
private TagService tagService;
public TagAdapter(List<Tag> tags, TagService tagService) {
this.tags = tags != null ? tags : new ArrayList<>();
this.tagService = tagService;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_tag, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Tag tag = tags.get(position);
holder.tagName.setText(tag.getName());
// 实时查询关联记录数量
int recordCount = tagService.getTagRecordCount(tag.getId());
holder.recordCount.setText("关联记录: " + recordCount);
// 设置整个标签项的点击事件
holder.itemView.setOnClickListener(v -> {
if (tagClickListener != null) {
tagClickListener.onTagClick(tag);
}
});
// 设置编辑按钮点击事件
holder.editButton.setOnClickListener(v -> {
if (operationListener != null) {
operationListener.onEditTag(tag);
}
});
// 设置删除按钮点击事件
holder.deleteButton.setOnClickListener(v -> {
if (operationListener != null) {
operationListener.onDeleteTag(tag);
}
});
}
@Override
public int getItemCount() {
return tags.size();
}
public void updateData(List<Tag> newTags) {
this.tags = newTags != null ? newTags : new ArrayList<>();
notifyDataSetChanged();
}
public void setOnTagOperationListener(OnTagOperationListener listener) {
this.operationListener = listener;
}
public void setOnTagClickListener(OnTagClickListener listener) {
this.tagClickListener = listener;
}
public interface OnTagOperationListener {
void onEditTag(Tag tag);
void onDeleteTag(Tag tag);
}
public interface OnTagClickListener {
void onTagClick(Tag tag);
}
static class ViewHolder extends RecyclerView.ViewHolder {
TextView tagName;
TextView recordCount;
TextView editButton;
TextView deleteButton;
ViewHolder(View itemView) {
super(itemView);
tagName = itemView.findViewById(R.id.tag_name);
recordCount = itemView.findViewById(R.id.record_count);
editButton = itemView.findViewById(R.id.edit_button);
deleteButton = itemView.findViewById(R.id.delete_button);
}
}
}

@ -0,0 +1,378 @@
package com.translation.app;
import android.content.Context;
import android.content.SharedPreferences;
import com.translation.model.User;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import com.translation.model.Tag;
import java.util.ArrayList;
import java.util.List;
public class AppState {
private static final String TAG = "AppState";
private static AppState instance;
// SharedPreferences 键名
private static final String PREFS_NAME = "app_state";
private static final String KEY_LOGGED_IN = "is_logged_in";
private static final String KEY_CURRENT_USER = "current_user";
private static final String KEY_LAST_LOGIN_PHONE = "last_login_phone";
private static final String KEY_REMEMBER_PASSWORD = "remember_password";
private static final String KEY_USER_DATABASE = "user_database";
// 在 PREFS_NAME 常量附近添加:
private static final String KEY_TAGS = "tags";
private static final String KEY_AUTO_COPY_ENABLED = "auto_copy_enabled";
private SharedPreferences sharedPreferences;
private Gson gson;
// 应用状态
private boolean isLoggedIn = false;
private User currentUser = null;
private boolean isOnlineMode = true;
private boolean isVoiceInputEnabled = true;
// 用户数据库(模拟)
private Map<String, User> userDatabase;
// 模式切换监听器
private ModeChangeListener modeChangeListener;
private List<Tag> tags = new ArrayList<>();
private boolean autoCopyEnabled = false;
private AppState(Context context) {
this.sharedPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
this.gson = new Gson();
loadPersistedData();
}
public static synchronized AppState getInstance(Context context) {
if (instance == null) {
instance = new AppState(context);
}
return instance;
}
/**
*
*/
private void loadPersistedData() {
// 加载登录状态
isLoggedIn = sharedPreferences.getBoolean(KEY_LOGGED_IN, false);
// 加载记住密码设置
// 注意这里不需要加载密码密码应该由AuthService管理
// 加载用户数据库
loadUserDatabase();
// 加载标签
loadTags();
// 加载自动复制设置
autoCopyEnabled = sharedPreferences.getBoolean(KEY_AUTO_COPY_ENABLED, false);
// 加载当前用户(如果已登录)
if (isLoggedIn) {
loadCurrentUser();
}
}
/**
*
*/
private void loadUserDatabase() {
String userDbJson = sharedPreferences.getString(KEY_USER_DATABASE, null);
if (userDbJson != null) {
try {
Type type = new TypeToken<Map<String, User>>(){}.getType();
userDatabase = gson.fromJson(userDbJson, type);
} catch (Exception e) {
e.printStackTrace();
userDatabase = new HashMap<>();
}
} else {
userDatabase = new HashMap<>();
// 初始化一些测试用户
initializeTestUsers();
}
}
/**
*
*/
private void saveUserDatabase() {
String userDbJson = gson.toJson(userDatabase);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(KEY_USER_DATABASE, userDbJson);
editor.apply();
}
/**
*
*/
private void loadCurrentUser() {
String userJson = sharedPreferences.getString(KEY_CURRENT_USER, null);
if (userJson != null) {
try {
currentUser = gson.fromJson(userJson, User.class);
} catch (Exception e) {
e.printStackTrace();
currentUser = null;
isLoggedIn = false;
}
}
}
/**
*
*/
private void initializeTestUsers() {
userDatabase.put("13800138000", new User("13800138000", "测试用户1", "123456"));
userDatabase.put("13900139000", new User("13900139000", "测试用户2", "abcdef"));
userDatabase.put("13600136000", new User("13600136000", "测试用户3", "password123"));
saveUserDatabase();
}
// Getters and Setters
public boolean isLoggedIn() {
return isLoggedIn;
}
public void setLoggedIn(boolean loggedIn) {
this.isLoggedIn = loggedIn;
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean(KEY_LOGGED_IN, loggedIn);
editor.apply();
}
public User getCurrentUser() {
return currentUser;
}
public void setCurrentUser(User user) {
this.currentUser = user;
if (user != null) {
String userJson = gson.toJson(user);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(KEY_CURRENT_USER, userJson);
editor.apply();
// 同时更新用户数据库
if (!userDatabase.containsKey(user.getPhoneNumber())) {
userDatabase.put(user.getPhoneNumber(), user);
saveUserDatabase();
}
} else {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.remove(KEY_CURRENT_USER);
editor.apply();
}
}
public boolean isOnlineMode() {
return isOnlineMode;
}
public void setOnlineMode(boolean onlineMode) {
boolean oldMode = this.isOnlineMode;
this.isOnlineMode = onlineMode;
if (oldMode != onlineMode && modeChangeListener != null) {
modeChangeListener.onModeChanged(onlineMode);
}
}
public boolean isVoiceInputEnabled() {
return isVoiceInputEnabled;
}
public void setVoiceInputEnabled(boolean voiceInputEnabled) {
this.isVoiceInputEnabled = voiceInputEnabled;
}
public void setModeChangeListener(ModeChangeListener listener) {
this.modeChangeListener = listener;
}
public interface ModeChangeListener {
void onModeChanged(boolean isOnlineMode);
}
/**
* AuthService使
*/
public Map<String, User> getUserDatabase() {
return userDatabase;
}
/**
* AuthService使
*/
public void saveUserToDatabase(String phoneNumber, User user) {
userDatabase.put(phoneNumber, user);
saveUserDatabase();
}
/**
*
*/
public User getUserFromDatabase(String phoneNumber) {
return userDatabase.get(phoneNumber);
}
/**
*
*/
public boolean userExists(String phoneNumber) {
return userDatabase.containsKey(phoneNumber);
}
/**
*
*/
public void saveLastLoginPhone(String phoneNumber) {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(KEY_LAST_LOGIN_PHONE, phoneNumber);
editor.apply();
}
/**
*
*/
public String getLastLoginPhone() {
return sharedPreferences.getString(KEY_LAST_LOGIN_PHONE, null);
}
/**
*
*/
public void setRememberPassword(boolean remember) {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean(KEY_REMEMBER_PASSWORD, remember);
editor.apply();
}
/**
*
*/
public boolean getRememberPassword() {
return sharedPreferences.getBoolean(KEY_REMEMBER_PASSWORD, false);
}
/**
* 退
*/
public void clearUserData() {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.remove(KEY_LOGGED_IN);
editor.remove(KEY_CURRENT_USER);
editor.remove(KEY_LAST_LOGIN_PHONE);
// 不清除记住密码设置和用户数据库
editor.apply();
isLoggedIn = false;
currentUser = null;
}
// 添加标签相关方法:
public List<Tag> getTags() {
return tags;
}
public void addTag(Tag tag) {
tags.add(tag);
saveTags();
}
public void removeTag(int tagId) {
tags.removeIf(tag -> tag.getId() == tagId);
saveTags();
}
private void loadTags() {
String tagsJson = sharedPreferences.getString(KEY_TAGS, null);
if (tagsJson != null) {
try {
Type listType = new TypeToken<List<Tag>>(){}.getType();
tags = gson.fromJson(tagsJson, listType);
} catch (Exception e) {
e.printStackTrace();
tags = new ArrayList<>();
}
} else {
tags = new ArrayList<>();
// 初始化一些默认标签
initializeDefaultTags();
}
}
private void saveTags() {
String tagsJson = gson.toJson(tags);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(KEY_TAGS, tagsJson);
editor.apply();
}
private void initializeDefaultTags() {
tags.add(new Tag(1, "日常用语", 0));
tags.add(new Tag(2, "商务", 0));
tags.add(new Tag(3, "旅游", 0));
tags.add(new Tag(4, "学习", 0));
tags.add(new Tag(5, "工作", 0));
saveTags();
}
// 自动复制功能相关方法:
public boolean isAutoCopyEnabled() {
return autoCopyEnabled;
}
public void setAutoCopyEnabled(boolean enabled) {
this.autoCopyEnabled = enabled;
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean(KEY_AUTO_COPY_ENABLED, enabled);
editor.apply();
}
// 添加一个公共的保存方法(如果需要):
public void saveAllData() {
saveUserDatabase();
saveTags();
}
// 在 AppState.java 中添加这个方法(如果不存在)
public boolean createTag(String tagName) {
if (tagName == null || tagName.trim().isEmpty()) {
return false;
}
String trimmedName = tagName.trim();
// 检查是否已存在
for (Tag tag : tags) {
if (tag.getName().equals(trimmedName)) {
return false;
}
}
// 生成新ID
int newId = 1;
for (Tag tag : tags) {
if (tag.getId() >= newId) {
newId = tag.getId() + 1;
}
}
// 创建新标签
Tag newTag = new Tag(newId, trimmedName, 0);
tags.add(newTag);
saveTags(); // 保存到 SharedPreferences
return true;
}
}

@ -0,0 +1,154 @@
package com.translation.app;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
import com.huawei.hms.mlsdk.common.MLApplication;
public class HuaweiMLKitConfig {
private static final String TAG = "HuaweiMLKitConfig";
private static final String PREF_NAME = "huawei_mlkit_config";
private static final String KEY_APP_ID = "app_id";
private static final String KEY_INITIALIZED = "initialized";
private static HuaweiMLKitConfig instance;
private final Context context;
private final SharedPreferences preferences;
private boolean isInitialized = false;
private HuaweiMLKitConfig(Context context) {
this.context = context.getApplicationContext();
this.preferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
}
public static synchronized HuaweiMLKitConfig getInstance(Context context) {
if (instance == null) {
instance = new HuaweiMLKitConfig(context);
}
return instance;
}
/**
* ML Kit
*/
public boolean initialize(String appId) {
try {
if (appId == null || appId.trim().isEmpty()) {
Log.e(TAG, "App ID 不能为空");
return false;
}
// 设置华为 ML Kit 应用ID
MLApplication.getInstance().setApiKey(appId.trim());
// 保存配置
saveAppId(appId.trim());
setInitialized(true);
this.isInitialized = true;
Log.d(TAG, "华为 ML Kit 配置初始化成功");
return true;
} catch (Exception e) {
Log.e(TAG, "华为 ML Kit 配置初始化失败: " + e.getMessage(), e);
return false;
}
}
/**
*
*/
public boolean restoreInitialization() {
if (isInitialized()) {
String savedAppId = getSavedAppId();
if (savedAppId != null && !savedAppId.isEmpty()) {
try {
MLApplication.getInstance().setApiKey(savedAppId);
this.isInitialized = true;
Log.d(TAG, "华为 ML Kit 配置从保存状态恢复");
return true;
} catch (Exception e) {
Log.e(TAG, "恢复华为 ML Kit 配置失败: " + e.getMessage());
}
}
}
return false;
}
/**
* App ID
*/
private void saveAppId(String appId) {
preferences.edit()
.putString(KEY_APP_ID, appId)
.apply();
}
/**
* App ID
*/
public String getSavedAppId() {
return preferences.getString(KEY_APP_ID, null);
}
/**
*
*/
private void setInitialized(boolean initialized) {
preferences.edit()
.putBoolean(KEY_INITIALIZED, initialized)
.apply();
this.isInitialized = initialized;
}
/**
*
*/
public boolean isInitialized() {
return preferences.getBoolean(KEY_INITIALIZED, false) || this.isInitialized;
}
/**
*
*/
public void clearConfig() {
preferences.edit()
.remove(KEY_APP_ID)
.remove(KEY_INITIALIZED)
.apply();
this.isInitialized = false;
Log.d(TAG, "华为 ML Kit 配置已清除");
}
/**
*
*/
public String getConfigInfo() {
boolean initialized = isInitialized();
String appId = getSavedAppId();
String appIdStatus = appId != null ? "已设置" : "未设置";
if (appId != null && appId.length() > 8) {
appIdStatus = appId.substring(0, 4) + "****" + appId.substring(appId.length() - 4);
}
return String.format("已初始化: %s, App ID: %s",
initialized ? "是" : "否",
appIdStatus);
}
/**
*
*/
public boolean isHmsAvailable() {
try {
// 检查 HMS Core 是否安装
return com.huawei.hms.api.HuaweiApiAvailability.getInstance()
.isHuaweiMobileServicesAvailable(context) == com.huawei.hms.api.ConnectionResult.SUCCESS;
} catch (Exception e) {
Log.e(TAG, "检查 HMS 可用性失败: " + e.getMessage());
return false;
}
}
}

@ -0,0 +1,22 @@
package com.translation.app;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 直接跳转到登录页面
startLoginActivity();
}
private void startLoginActivity() {
android.content.Intent intent = new android.content.Intent(this, com.translation.activity.LoginActivity.class);
startActivity(intent);
finish();
}
}

@ -0,0 +1,104 @@
package com.translation.app;
import android.app.Application;
import android.util.Log;
public class TranslationApp extends Application {
private static final String TAG = "TranslationApp";
private HuaweiMLKitConfig huaweiConfig;
private static TranslationApp instance;
@Override
public void onCreate() {
super.onCreate();
instance = this;
Log.d(TAG, "应用初始化开始");
// 初始化AppState
AppState.getInstance(this);
Log.d(TAG, "AppState 初始化完成");
// 初始化华为 ML Kit 配置
initializeHuaweiMLKit();
Log.d(TAG, "应用初始化完成");
}
/**
*
*/
public static TranslationApp getInstance() {
return instance;
}
/**
* ML Kit
*/
private void initializeHuaweiMLKit() {
try {
huaweiConfig = HuaweiMLKitConfig.getInstance(this);
// 检查 HMS 可用性
if (!huaweiConfig.isHmsAvailable()) {
Log.w(TAG, "华为移动服务不可用,请安装 HMS Core");
return;
}
// 尝试从保存的配置恢复初始化0·
if (huaweiConfig.restoreInitialization()) {
Log.d(TAG, "华为 ML Kit 从保存的配置恢复初始化成功");
} else {
Log.w(TAG, "华为 ML Kit 需要手动初始化,请在设置中配置 App ID");
}
Log.d(TAG, "华为 ML Kit 配置状态: " + huaweiConfig.getConfigInfo());
} catch (Exception e) {
Log.e(TAG, "华为 ML Kit 初始化失败: " + e.getMessage(), e);
}
}
/**
* ML Kit
*/
public HuaweiMLKitConfig getHuaweiMLKitConfig() {
return huaweiConfig;
}
/**
* ML Kit
*/
public boolean initializeHuaweiMLKitWithAppId(String appId) {
if (huaweiConfig != null) {
return huaweiConfig.initialize(appId);
}
return false;
}
/**
* ML Kit
*/
public boolean isHuaweiMLKitAvailable() {
return huaweiConfig != null && huaweiConfig.isInitialized() && huaweiConfig.isHmsAvailable();
}
/**
* ML Kit
*/
public String getHuaweiMLKitStatus() {
if (huaweiConfig != null) {
return huaweiConfig.getConfigInfo();
}
return "华为 ML Kit 未初始化";
}
/**
* ML Kit
*/
public void clearHuaweiMLKitConfig() {
if (huaweiConfig != null) {
huaweiConfig.clearConfig();
}
}
}

@ -0,0 +1,361 @@
package com.translation.config;
import android.util.Log;
import okhttp3.OkHttpClient;
import java.util.concurrent.TimeUnit;
public class BaiduApiConfig {
private static final String TAG = "BaiduApiConfig";
// 枚举类型,标识使用哪一套配置
public enum ConfigType {
TEXT_TRANSLATION, // 文字翻译
DOCUMENT_TRANSLATION, // 文档翻译
SPEECH_TRANSLATION, // 语音翻译
SPEECH_RECOGNITION, // 语音识别/音频转写
TEXT_RECOGNITION, // 文字识别原百度翻译OCR现改为百度云OCR
CLOUD_OCR // 新增百度云文字识别OCR
}
// 百度翻译开放平台配置
private static final String BAIDU_TRANSLATE_APP_ID = "20251024002482063";
private static final String BAIDU_TRANSLATE_SECRET_KEY = "aIArIWSvD7cEHS5T5Nfm";
// 百度云语音技术配置(需要单独申请)
private static final String BAIDU_SPEECH_APP_ID = "120485837"; // 需要替换为实际的语音识别APP_ID
private static final String BAIDU_SPEECH_API_KEY = "90D1e0lQ4zFSXkq4EDyBWyAh"; // 需要替换为实际的语音识别API_KEY
private static final String BAIDU_SPEECH_SECRET_KEY = "d8TPHLMSiB1xq0kKje0rSWQ2a3zn4xyp"; // 需要替换为实际的语音识别SECRET_KEY
// 新增:百度云文字识别配置(需要单独申请)
private static final String BAIDU_OCR_APP_ID = "120920717"; // 需要替换为实际的OCR APP_ID
private static final String BAIDU_OCR_API_KEY = "94mSVyVwtlkBl9PtYzbZOzcv"; // 需要替换为实际的OCR API_KEY
private static final String BAIDU_OCR_SECRET_KEY = "rsIqXJVqvHsO7HI4amsRpR83fWondCSS"; // 需要替换为实际的OCR SECRET_KEY
// 文字翻译应用配置 - 百度翻译开放平台
private static final String TEXT_TRANSLATION_APP_ID = BAIDU_TRANSLATE_APP_ID;
private static final String TEXT_TRANSLATION_SECRET_KEY = BAIDU_TRANSLATE_SECRET_KEY;
// 文档翻译应用配置 - 百度翻译
private static final String DOCUMENT_TRANSLATION_APP_ID = BAIDU_TRANSLATE_APP_ID;
private static final String DOCUMENT_TRANSLATION_SECRET_KEY = BAIDU_TRANSLATE_SECRET_KEY;
// 语音翻译应用配置 - 百度翻译
private static final String SPEECH_TRANSLATION_APP_ID = BAIDU_TRANSLATE_APP_ID;
private static final String SPEECH_TRANSLATION_SECRET_KEY = BAIDU_TRANSLATE_SECRET_KEY;
// 语音识别/音频转写应用配置 - 百度云语音技术
private static final String SPEECH_RECOGNITION_APP_ID = BAIDU_SPEECH_APP_ID;
private static final String SPEECH_RECOGNITION_API_KEY = BAIDU_SPEECH_API_KEY;
private static final String SPEECH_RECOGNITION_SECRET_KEY = BAIDU_SPEECH_SECRET_KEY;
// 文字识别应用配置 - 百度翻译原OCR功能
private static final String TEXT_RECOGNITION_APP_ID = BAIDU_TRANSLATE_APP_ID;
private static final String TEXT_RECOGNITION_SECRET_KEY = BAIDU_TRANSLATE_SECRET_KEY;
// 新增:百度云文字识别应用配置
private static final String CLOUD_OCR_APP_ID = BAIDU_OCR_APP_ID;
private static final String CLOUD_OCR_API_KEY = BAIDU_OCR_API_KEY;
private static final String CLOUD_OCR_SECRET_KEY = BAIDU_OCR_SECRET_KEY;
// API端点配置
public static final String TEXT_TRANSLATE_API_URL = "https://api.fanyi.baidu.com/api/trans/vip/translate";
public static final String DOCUMENT_TRANSLATE_API_URL = "https://fanyi-api.baidu.com/api/trans/vip/doctrans";
public static final String SPEECH_TRANSLATE_API_URL = "https://fanyi-api.baidu.com/api/trans/v2/voicetrans";
// 百度云语音识别API端点
public static final String SPEECH_ASR_API_URL = "https://vop.baidu.com/server_api";
// 文字识别使用文字翻译API原OCR功能
public static final String TEXT_RECOGNITION_API_URL = "https://api.fanyi.baidu.com/api/trans/vip/translate";
// 新增百度云文字识别API端点
public static final String CLOUD_OCR_API_URL = "https://aip.baidubce.com/rest/2.0/ocr/v1/";
// 百度云Token获取端点
public static final String TOKEN_URL = "https://aip.baidubce.com/oauth/2.0/token";
// 共享的HTTP客户端
private static OkHttpClient sharedHttpClient;
public static OkHttpClient getHttpClient() {
if (sharedHttpClient == null) {
sharedHttpClient = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build();
Log.d(TAG, "创建共享HTTP客户端");
}
return sharedHttpClient;
}
// 根据类型获取配置
public static String getAppId(ConfigType type) {
switch (type) {
case TEXT_TRANSLATION: return TEXT_TRANSLATION_APP_ID;
case DOCUMENT_TRANSLATION: return DOCUMENT_TRANSLATION_APP_ID;
case SPEECH_TRANSLATION: return SPEECH_TRANSLATION_APP_ID;
case SPEECH_RECOGNITION: return SPEECH_RECOGNITION_APP_ID;
case TEXT_RECOGNITION: return TEXT_RECOGNITION_APP_ID;
case CLOUD_OCR: return CLOUD_OCR_APP_ID;
default: return BAIDU_TRANSLATE_APP_ID;
}
}
public static String getApiKey(ConfigType type) {
switch (type) {
case SPEECH_RECOGNITION: return SPEECH_RECOGNITION_API_KEY;
case CLOUD_OCR: return CLOUD_OCR_API_KEY;
// 其他服务使用百度翻译不需要API_KEY
default: return null;
}
}
public static String getSecretKey(ConfigType type) {
switch (type) {
case TEXT_TRANSLATION: return TEXT_TRANSLATION_SECRET_KEY;
case DOCUMENT_TRANSLATION: return DOCUMENT_TRANSLATION_SECRET_KEY;
case SPEECH_TRANSLATION: return SPEECH_TRANSLATION_SECRET_KEY;
case SPEECH_RECOGNITION: return SPEECH_RECOGNITION_SECRET_KEY;
case TEXT_RECOGNITION: return TEXT_RECOGNITION_SECRET_KEY;
case CLOUD_OCR: return CLOUD_OCR_SECRET_KEY;
default: return BAIDU_TRANSLATE_SECRET_KEY;
}
}
// 获取对应功能的API URL
public static String getApiUrl(ConfigType type) {
switch (type) {
case TEXT_TRANSLATION: return TEXT_TRANSLATE_API_URL;
case DOCUMENT_TRANSLATION: return DOCUMENT_TRANSLATE_API_URL;
case SPEECH_TRANSLATION: return SPEECH_TRANSLATE_API_URL;
case SPEECH_RECOGNITION: return SPEECH_ASR_API_URL;
case TEXT_RECOGNITION: return TEXT_RECOGNITION_API_URL;
case CLOUD_OCR: return CLOUD_OCR_API_URL;
default: return TEXT_TRANSLATE_API_URL;
}
}
// 验证配置
public static void validateConfig(ConfigType type) {
Log.d(TAG, "=== 百度API配置验证 ===");
Log.d(TAG, "使用配置: " + type);
Log.d(TAG, "功能描述: " + getFunctionDescription(type));
Log.d(TAG, "服务提供商: " + getServiceProvider(type));
Log.d(TAG, "APP_ID: " + getAppId(type));
String apiKey = getApiKey(type);
if (apiKey != null) {
Log.d(TAG, "API_KEY: " + (apiKey.length() > 6 ? apiKey.substring(0, 6) + "..." : apiKey));
} else {
Log.d(TAG, "API_KEY: 不需要");
}
Log.d(TAG, "API_URL: " + getApiUrl(type));
String secretKey = getSecretKey(type);
Log.d(TAG, "SECRET_KEY长度: " + (secretKey != null ? secretKey.length() : "null"));
Log.d(TAG, "SECRET_KEY前6位: " + (secretKey != null && secretKey.length() > 6 ? secretKey.substring(0, 6) + "..." : secretKey));
// 检查语音识别配置
if (type == ConfigType.SPEECH_RECOGNITION) {
Log.d(TAG, "=== 语音识别配置详情 ===");
Log.d(TAG, "服务类型: 百度云语音技术");
Log.d(TAG, "需要单独申请语音识别服务");
if (SPEECH_RECOGNITION_APP_ID.equals("YOUR_SPEECH_APP_ID")) {
Log.w(TAG, "警告: 语音识别APP_ID未配置请替换为实际值");
}
if (SPEECH_RECOGNITION_API_KEY.equals("YOUR_SPEECH_API_KEY")) {
Log.w(TAG, "警告: 语音识别API_KEY未配置请替换为实际值");
}
}
// 检查百度云OCR配置
if (type == ConfigType.CLOUD_OCR) {
Log.d(TAG, "=== 百度云文字识别配置详情 ===");
Log.d(TAG, "服务类型: 百度云文字识别(OCR)");
if (CLOUD_OCR_APP_ID.equals("YOUR_OCR_APP_ID")) {
Log.w(TAG, "警告: 文字识别APP_ID未配置请替换为实际值");
}
if (CLOUD_OCR_API_KEY.equals("YOUR_OCR_API_KEY")) {
Log.w(TAG, "警告: 文字识别API_KEY未配置请替换为实际值");
}
}
// 检查翻译相关服务
if (isTranslationService(type)) {
Log.d(TAG, "=== 翻译服务配置详情 ===");
Log.d(TAG, "服务类型: 百度翻译开放平台");
}
}
// 获取功能描述(用于日志或显示)
public static String getFunctionDescription(ConfigType type) {
switch (type) {
case TEXT_TRANSLATION: return "文字翻译";
case DOCUMENT_TRANSLATION: return "文档翻译";
case SPEECH_TRANSLATION: return "语音翻译";
case SPEECH_RECOGNITION: return "语音识别";
case TEXT_RECOGNITION: return "文字识别(翻译OCR)";
case CLOUD_OCR: return "百度云文字识别(OCR)";
default: return "未知功能";
}
}
// 检查服务是否可用
public static boolean isServiceAvailable(ConfigType type) {
String appId = getAppId(type);
String secretKey = getSecretKey(type);
// 对于语音识别和OCR还需要检查API_KEY
if (type == ConfigType.SPEECH_RECOGNITION || type == ConfigType.CLOUD_OCR) {
String apiKey = getApiKey(type);
return appId != null && !appId.isEmpty() &&
!appId.equals("YOUR_SPEECH_APP_ID") && !appId.equals("YOUR_OCR_APP_ID") &&
apiKey != null && !apiKey.isEmpty() &&
!apiKey.equals("YOUR_SPEECH_API_KEY") && !apiKey.equals("YOUR_OCR_API_KEY") &&
secretKey != null && !secretKey.isEmpty() &&
!secretKey.equals("YOUR_SPEECH_SECRET_KEY") && !secretKey.equals("YOUR_OCR_SECRET_KEY");
}
// 对于其他服务
return appId != null && !appId.isEmpty() &&
secretKey != null && !secretKey.isEmpty();
}
// 获取音频格式信息
public static String getAudioFormatInfo(ConfigType type) {
if (type == ConfigType.SPEECH_TRANSLATION || type == ConfigType.SPEECH_RECOGNITION) {
return "支持格式: wav/pcm/amr, 采样率: 16000Hz, 声道: 单声道, 最大大小: 10MB";
}
return "不适用";
}
// 判断配置类型是否使用百度翻译API
public static boolean isBaiduTranslateApi(ConfigType type) {
return type == ConfigType.TEXT_TRANSLATION ||
type == ConfigType.DOCUMENT_TRANSLATION ||
type == ConfigType.SPEECH_TRANSLATION ||
type == ConfigType.TEXT_RECOGNITION;
}
// 判断配置类型是否使用百度云API
public static boolean isBaiduCloudApi(ConfigType type) {
return type == ConfigType.SPEECH_RECOGNITION || type == ConfigType.CLOUD_OCR;
}
// 获取服务提供商信息
public static String getServiceProvider(ConfigType type) {
if (isBaiduCloudApi(type)) {
if (type == ConfigType.SPEECH_RECOGNITION) {
return "百度云语音技术";
} else if (type == ConfigType.CLOUD_OCR) {
return "百度云文字识别";
}
}
return "百度翻译开放平台";
}
// 判断是否为翻译服务
public static boolean isTranslationService(ConfigType type) {
return type == ConfigType.TEXT_TRANSLATION ||
type == ConfigType.DOCUMENT_TRANSLATION ||
type == ConfigType.SPEECH_TRANSLATION;
}
// 获取文档翻译支持的文件格式
public static String getDocumentTranslationFormats() {
return "支持格式: .doc, .docx, .pdf, .ppt, .pptx, .xls, .xlsx, .txt";
}
// 获取OCR支持的文件格式
public static String getOcrSupportedFormats() {
return "支持格式: JPG, JPEG, PNG, BMP, PDF; 最大大小: 4MB";
}
// 获取统一的应用ID用于显示
public static String getUnifiedAppId() {
return BAIDU_TRANSLATE_APP_ID;
}
// 获取所有服务的状态信息
public static String getAllServicesStatus() {
StringBuilder status = new StringBuilder();
status.append("=== 百度API服务状态 ===\n\n");
status.append("翻译服务 (百度翻译开放平台):\n");
status.append("应用ID: ").append(BAIDU_TRANSLATE_APP_ID).append("\n\n");
for (ConfigType type : ConfigType.values()) {
String provider = getServiceProvider(type);
boolean available = isServiceAvailable(type);
status.append(getFunctionDescription(type))
.append(" (").append(provider).append(")")
.append(": ")
.append(available ? "✓ 可用" : "✗ 需要配置")
.append("\n");
}
status.append("\n配置说明:\n");
status.append("- 语音识别需要单独申请百度云语音技术服务\n");
status.append("- 文字识别需要单独申请百度云OCR服务\n");
status.append("- 请替换 BaiduApiConfig.java 中的对应配置参数");
return status.toString();
}
// 新增方法获取语音识别访问令牌URL
public static String getSpeechTokenUrl() {
return TOKEN_URL + "?grant_type=client_credentials" +
"&client_id=" + SPEECH_RECOGNITION_API_KEY +
"&client_secret=" + SPEECH_RECOGNITION_SECRET_KEY;
}
// 新增方法获取OCR访问令牌URL
public static String getOcrTokenUrl() {
return TOKEN_URL + "?grant_type=client_credentials" +
"&client_id=" + CLOUD_OCR_API_KEY +
"&client_secret=" + CLOUD_OCR_SECRET_KEY;
}
// 新增方法:检查语音识别配置是否完整
public static boolean isSpeechRecognitionConfigured() {
return isServiceAvailable(ConfigType.SPEECH_RECOGNITION);
}
// 新增方法检查OCR配置是否完整
public static boolean isOcrConfigured() {
return isServiceAvailable(ConfigType.CLOUD_OCR);
}
// 新增方法:获取配置提示信息
public static String getConfigurationHint(ConfigType type) {
if (type == ConfigType.SPEECH_RECOGNITION && !isServiceAvailable(type)) {
return "语音识别服务需要单独配置:\n" +
"1. 访问百度云控制台 (ai.baidu.com)\n" +
"2. 创建语音技术应用\n" +
"3. 获取 API_KEY 和 SECRET_KEY\n" +
"4. 更新 BaiduApiConfig.java 中的配置";
}
if (type == ConfigType.CLOUD_OCR && !isServiceAvailable(type)) {
return "文字识别服务需要单独配置:\n" +
"1. 访问百度云控制台 (ai.baidu.com)\n" +
"2. 创建文字识别应用\n" +
"3. 获取 API_KEY 和 SECRET_KEY\n" +
"4. 更新 BaiduApiConfig.java 中的OCR配置";
}
return "服务已配置";
}
// 新增方法获取OCR API的具体接口URL
public static String getOcrApiUrl(String ocrType) {
// ocrType 可以是: general_basic(通用文字识别), accurate_basic(通用文字识别高精度版),
// idcard(身份证识别), bankcard(银行卡识别)等
return CLOUD_OCR_API_URL + ocrType;
}
}

@ -0,0 +1,385 @@
// TranslationDatabaseHelper.java
package com.translation.database;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import com.translation.model.TranslationRecord;
import java.util.ArrayList;
import java.util.List;
public class TranslationDatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = "TranslationDatabaseHelper";
private static final String DATABASE_NAME = "translation_history.db";
private static final int DATABASE_VERSION = 1;
// 表名和列名
public static final String TABLE_HISTORY = "translation_history";
public static final String COLUMN_ID = "id";
public static final String COLUMN_SOURCE_TEXT = "source_text";
public static final String COLUMN_TARGET_TEXT = "target_text";
public static final String COLUMN_SOURCE_LANG = "source_lang";
public static final String COLUMN_TARGET_LANG = "target_lang";
public static final String COLUMN_TIMESTAMP = "timestamp";
public static final String COLUMN_TAGS = "tags";
// 创建表SQL
private static final String CREATE_TABLE_HISTORY =
"CREATE TABLE " + TABLE_HISTORY + "(" +
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
COLUMN_SOURCE_TEXT + " TEXT NOT NULL," +
COLUMN_TARGET_TEXT + " TEXT NOT NULL," +
COLUMN_SOURCE_LANG + " TEXT NOT NULL," +
COLUMN_TARGET_LANG + " TEXT NOT NULL," +
COLUMN_TIMESTAMP + " TEXT NOT NULL," +
COLUMN_TAGS + " TEXT" +
")";
public TranslationDatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE_HISTORY);
Log.d(TAG, "数据库表创建成功");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_HISTORY);
onCreate(db);
}
/**
*
*/
public long insertTranslationRecord(TranslationRecord record) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(COLUMN_SOURCE_TEXT, record.getSourceText());
values.put(COLUMN_TARGET_TEXT, record.getTargetText());
values.put(COLUMN_SOURCE_LANG, record.getSourceLang());
values.put(COLUMN_TARGET_LANG, record.getTargetLang());
values.put(COLUMN_TIMESTAMP, record.getTimestamp());
values.put(COLUMN_TAGS, android.text.TextUtils.join(",", record.getTags()));
long id = db.insert(TABLE_HISTORY, null, values);
db.close();
Log.d(TAG, "插入记录成功ID: " + id);
return id;
}
/**
*
*/
public List<TranslationRecord> getAllHistory() {
List<TranslationRecord> records = new ArrayList<>();
SQLiteDatabase db = this.getReadableDatabase();
String query = "SELECT * FROM " + TABLE_HISTORY + " ORDER BY " + COLUMN_TIMESTAMP + " DESC";
Cursor cursor = db.rawQuery(query, null);
if (cursor.moveToFirst()) {
do {
TranslationRecord record = cursorToTranslationRecord(cursor);
records.add(record);
} while (cursor.moveToNext());
}
cursor.close();
db.close();
return records;
}
/**
*
*/
public List<TranslationRecord> searchHistory(String keyword) {
List<TranslationRecord> records = new ArrayList<>();
SQLiteDatabase db = this.getReadableDatabase();
String query = "SELECT * FROM " + TABLE_HISTORY +
" WHERE " + COLUMN_SOURCE_TEXT + " LIKE ? OR " + COLUMN_TARGET_TEXT + " LIKE ?" +
" ORDER BY " + COLUMN_TIMESTAMP + " DESC";
Cursor cursor = db.rawQuery(query, new String[]{"%" + keyword + "%", "%" + keyword + "%"});
if (cursor.moveToFirst()) {
do {
TranslationRecord record = cursorToTranslationRecord(cursor);
records.add(record);
} while (cursor.moveToNext());
}
cursor.close();
db.close();
return records;
}
/**
*
*/
public List<TranslationRecord> filterByLanguage(String language) {
List<TranslationRecord> records = new ArrayList<>();
SQLiteDatabase db = this.getReadableDatabase();
String query = "SELECT * FROM " + TABLE_HISTORY +
" WHERE " + COLUMN_SOURCE_LANG + " = ? OR " + COLUMN_TARGET_LANG + " = ?" +
" ORDER BY " + COLUMN_TIMESTAMP + " DESC";
Cursor cursor = db.rawQuery(query, new String[]{language, language});
if (cursor.moveToFirst()) {
do {
TranslationRecord record = cursorToTranslationRecord(cursor);
records.add(record);
} while (cursor.moveToNext());
}
cursor.close();
db.close();
return records;
}
/**
*
*/
public boolean isRecordExists(String sourceText, String targetText, String sourceLang, String targetLang) {
SQLiteDatabase db = this.getReadableDatabase();
String query = "SELECT COUNT(*) FROM " + TABLE_HISTORY +
" WHERE " + COLUMN_SOURCE_TEXT + " = ? AND " + COLUMN_TARGET_TEXT + " = ? AND " +
COLUMN_SOURCE_LANG + " = ? AND " + COLUMN_TARGET_LANG + " = ?";
Cursor cursor = db.rawQuery(query, new String[]{sourceText, targetText, sourceLang, targetLang});
boolean exists = false;
if (cursor.moveToFirst()) {
exists = cursor.getInt(0) > 0;
}
cursor.close();
db.close();
return exists;
}
/**
*
*/
public void deleteRecords(List<Integer> recordIds) {
if (recordIds.isEmpty()) return;
SQLiteDatabase db = this.getWritableDatabase();
// 构建IN条件
StringBuilder whereClause = new StringBuilder(COLUMN_ID + " IN (");
for (int i = 0; i < recordIds.size(); i++) {
whereClause.append("?");
if (i < recordIds.size() - 1) {
whereClause.append(",");
}
}
whereClause.append(")");
// 构建参数数组
String[] whereArgs = new String[recordIds.size()];
for (int i = 0; i < recordIds.size(); i++) {
whereArgs[i] = String.valueOf(recordIds.get(i));
}
db.delete(TABLE_HISTORY, whereClause.toString(), whereArgs);
db.close();
Log.d(TAG, "删除记录完成,删除数量: " + recordIds.size());
}
/**
*
*/
public void clearAllHistory() {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_HISTORY, null, null);
db.close();
Log.d(TAG, "已清空所有历史记录");
}
/**
*
*/
public int getRecordCount() {
SQLiteDatabase db = this.getReadableDatabase();
String query = "SELECT COUNT(*) FROM " + TABLE_HISTORY;
Cursor cursor = db.rawQuery(query, null);
int count = 0;
if (cursor.moveToFirst()) {
count = cursor.getInt(0);
}
cursor.close();
db.close();
return count;
}
/**
* ID
*/
public int getOldestRecordId() {
SQLiteDatabase db = this.getReadableDatabase();
String query = "SELECT " + COLUMN_ID + " FROM " + TABLE_HISTORY +
" ORDER BY " + COLUMN_TIMESTAMP + " ASC LIMIT 1";
Cursor cursor = db.rawQuery(query, null);
int oldestId = -1;
if (cursor.moveToFirst()) {
oldestId = cursor.getInt(0);
}
cursor.close();
db.close();
return oldestId;
}
/**
* CursorTranslationRecord
*/
private TranslationRecord cursorToTranslationRecord(Cursor cursor) {
int id = cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_ID));
String sourceText = cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_SOURCE_TEXT));
String targetText = cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_TARGET_TEXT));
String sourceLang = cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_SOURCE_LANG));
String targetLang = cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_TARGET_LANG));
String timestamp = cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_TIMESTAMP));
String tagsString = cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_TAGS));
List<String> tags = new ArrayList<>();
if (tagsString != null && !tagsString.isEmpty()) {
String[] tagArray = tagsString.split(",");
for (String tag : tagArray) {
if (!tag.trim().isEmpty()) {
tags.add(tag.trim());
}
}
}
return new TranslationRecord(id, sourceText, targetText, sourceLang, targetLang, timestamp, tags);
}
// 在 TranslationDatabaseHelper.java 末尾添加这些方法
/**
*
*/
public boolean updateRecordTags(int recordId, List<String> tagNames) {
try {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
String tagsString = "";
if (tagNames != null && !tagNames.isEmpty()) {
tagsString = android.text.TextUtils.join(",", tagNames);
}
values.put(COLUMN_TAGS, tagsString);
int rowsAffected = db.update(TABLE_HISTORY, values,
COLUMN_ID + " = ?",
new String[]{String.valueOf(recordId)});
db.close();
boolean success = rowsAffected > 0;
if (success) {
Log.d(TAG, "更新记录标签成功记录ID: " + recordId);
} else {
Log.e(TAG, "更新记录标签失败记录ID: " + recordId);
}
return success;
} catch (Exception e) {
Log.e(TAG, "更新记录标签异常: " + e.getMessage(), e);
return false;
}
}
/**
*
*/
public List<TranslationRecord> filterByTags(List<String> tagNames) {
List<TranslationRecord> records = new ArrayList<>();
if (tagNames == null || tagNames.isEmpty()) {
return getAllHistory();
}
SQLiteDatabase db = this.getReadableDatabase();
// 构建查询条件检查tags列是否包含任一标签
StringBuilder whereClause = new StringBuilder();
String[] whereArgs = new String[tagNames.size()];
for (int i = 0; i < tagNames.size(); i++) {
if (i > 0) {
whereClause.append(" OR ");
}
whereClause.append(COLUMN_TAGS).append(" LIKE ?");
whereArgs[i] = "%" + tagNames.get(i) + "%";
}
String query = "SELECT * FROM " + TABLE_HISTORY +
" WHERE " + whereClause.toString() +
" ORDER BY " + COLUMN_TIMESTAMP + " DESC";
Cursor cursor = db.rawQuery(query, whereArgs);
if (cursor.moveToFirst()) {
do {
TranslationRecord record = cursorToTranslationRecord(cursor);
records.add(record);
} while (cursor.moveToNext());
}
cursor.close();
db.close();
return records;
}
/**
* 使
*/
public List<String> getAllUsedTags() {
List<String> usedTags = new ArrayList<>();
SQLiteDatabase db = this.getReadableDatabase();
String query = "SELECT " + COLUMN_TAGS + " FROM " + TABLE_HISTORY +
" WHERE " + COLUMN_TAGS + " IS NOT NULL AND " + COLUMN_TAGS + " != ''";
Cursor cursor = db.rawQuery(query, null);
if (cursor.moveToFirst()) {
do {
String tagsString = cursor.getString(0);
if (tagsString != null && !tagsString.isEmpty()) {
String[] tagArray = tagsString.split(",");
for (String tag : tagArray) {
String trimmedTag = tag.trim();
if (!trimmedTag.isEmpty() && !usedTags.contains(trimmedTag)) {
usedTags.add(trimmedTag);
}
}
}
} while (cursor.moveToNext());
}
cursor.close();
db.close();
return usedTags;
}
}

@ -0,0 +1,642 @@
package com.translation.model;
import android.content.Context;
import android.content.res.AssetManager;
import android.util.Log;
import com.translation.service.MLKitTranslationService;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* 线 - 线
*/
public class EnhancedOfflineTranslationModel {
private static final String TAG = "EnhancedOfflineTranslation";
private static EnhancedOfflineTranslationModel instance;
private Context context;
// 翻译引擎
private MLKitTranslationService mlKitService;
private boolean mlKitAvailable = false;
// 增强的词典管理
private Map<String, Map<String, String>> wordDictionaries;
private Map<String, Map<String, String>> phraseDictionaries;
private Map<String, String> commonPhrases;
private boolean isDictionaryEnhanced = false;
// 翻译统计
private int mlKitSuccessCount = 0;
private int dictionarySuccessCount = 0;
private int fallbackCount = 0;
// 回调接口
public interface TranslationCallback {
void onSuccess(String translatedText);
void onError(String errorMessage);
}
public interface DownloadCallback {
void onSuccess();
void onError(String errorMessage);
void onProgress(int progress);
}
public static synchronized EnhancedOfflineTranslationModel getInstance(Context context) {
if (instance == null) {
instance = new EnhancedOfflineTranslationModel(context);
}
return instance;
}
private EnhancedOfflineTranslationModel(Context context) {
this.context = context.getApplicationContext();
this.wordDictionaries = new HashMap<>();
this.phraseDictionaries = new HashMap<>();
this.commonPhrases = new HashMap<>();
initializeEnhancedSystem();
}
/**
*
*/
private void initializeEnhancedSystem() {
new Thread(() -> {
// 1. 初始化ML Kit
initializeMLKit();
// 2. 加载增强词典
loadEnhancedDictionaries();
// 3. 加载常用短语
loadEnhancedCommonPhrases();
Log.d(TAG, "✓ 增强离线翻译系统初始化完成");
Log.d(TAG, "词典统计: " + getDictionaryStats());
}).start();
}
/**
* ML Kit
*/
private void initializeMLKit() {
try {
mlKitService = new MLKitTranslationService(context);
mlKitAvailable = mlKitService.isInitialized();
Log.d(TAG, mlKitAvailable ? "✓ ML Kit 可用" : "⚠ ML Kit 不可用");
} catch (Exception e) {
Log.e(TAG, "✗ ML Kit 初始化失败: " + e.getMessage());
mlKitAvailable = false;
}
}
/**
*
*/
private void loadEnhancedDictionaries() {
try {
// 加载中英词典
loadEnhancedDictionary("dictionary_zh_en.json", "中文", "英语");
loadEnhancedDictionary("dictionary_en_zh.json", "英语", "中文");
// 可以继续加载其他语言词典
// loadEnhancedDictionary("dictionary_zh_ja.json", "中文", "日语");
// loadEnhancedDictionary("dictionary_ja_zh.json", "日语", "中文");
isDictionaryEnhanced = true;
Log.d(TAG, "✓ 增强词典加载完成");
} catch (Exception e) {
Log.e(TAG, "✗ 增强词典加载失败: " + e.getMessage());
}
}
/**
*
*/
private void loadEnhancedDictionary(String fileName, String sourceLang, String targetLang) {
try {
AssetManager assetManager = context.getAssets();
InputStream inputStream = assetManager.open(fileName);
BufferedReader reader = new BufferedReader(
new InputStreamReader(inputStream, "UTF-8"));
StringBuilder jsonContent = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
jsonContent.append(line);
}
JSONObject dictionaryJson = new JSONObject(jsonContent.toString());
JSONArray entries = dictionaryJson.getJSONArray("entries");
Map<String, String> wordDict = new HashMap<>();
Map<String, String> phraseDict = new HashMap<>();
for (int i = 0; i < entries.length(); i++) {
JSONObject entry = entries.getJSONObject(i);
String source = entry.getString("source").toLowerCase().trim();
String target = entry.getString("target");
// 根据内容长度判断是单词还是短语
if (source.contains(" ") || source.length() > 15) {
phraseDict.put(source, target);
} else {
wordDict.put(source, target);
}
}
String dictKey = generateDictionaryKey(sourceLang, targetLang);
wordDictionaries.put(dictKey, wordDict);
phraseDictionaries.put(dictKey, phraseDict);
Log.d(TAG, String.format("✓ 加载词典: %s->%s, 单词:%d, 短语:%d",
sourceLang, targetLang, wordDict.size(), phraseDict.size()));
} catch (Exception e) {
Log.e(TAG, "✗ 加载词典失败: " + fileName, e);
}
}
/**
*
*/
private void loadEnhancedCommonPhrases() {
// 问候语
commonPhrases.put("hello", "你好");
commonPhrases.put("hi", "你好");
commonPhrases.put("good morning", "早上好");
commonPhrases.put("good afternoon", "下午好");
commonPhrases.put("good evening", "晚上好");
commonPhrases.put("good night", "晚安");
// 礼貌用语
commonPhrases.put("thank you", "谢谢");
commonPhrases.put("thanks", "谢谢");
commonPhrases.put("sorry", "对不起");
commonPhrases.put("excuse me", "打扰一下");
commonPhrases.put("please", "请");
// 常用表达
commonPhrases.put("how are you", "你好吗");
commonPhrases.put("i love you", "我爱你");
commonPhrases.put("what's your name", "你叫什么名字");
commonPhrases.put("where are you from", "你来自哪里");
// 中文对应的英文
commonPhrases.put("你好", "hello");
commonPhrases.put("谢谢", "thank you");
commonPhrases.put("对不起", "sorry");
commonPhrases.put("早上好", "good morning");
commonPhrases.put("晚上好", "good evening");
commonPhrases.put("晚安", "good night");
}
/**
*
*/
public String translate(String text, String sourceLang, String targetLang) {
if (text == null || text.trim().isEmpty()) {
return text;
}
String trimmedText = text.trim();
Log.d(TAG, String.format("翻译请求: [%s] %s -> %s",
trimmedText, sourceLang, targetLang));
// 1. 检查常用短语(最高优先级)
String phraseResult = translateCommonPhrase(trimmedText, sourceLang, targetLang);
if (phraseResult != null) {
dictionarySuccessCount++;
return phraseResult;
}
// 2. 尝试ML Kit主引擎
if (mlKitAvailable && mlKitService != null) {
String mlKitResult = translateWithMLKit(trimmedText, sourceLang, targetLang);
if (isValidMLKitTranslation(mlKitResult, trimmedText)) {
mlKitSuccessCount++;
return mlKitResult;
}
}
// 3. 使用增强词典翻译
String dictResult = enhancedDictionaryTranslate(trimmedText, sourceLang, targetLang);
if (isValidDictionaryTranslation(dictResult, trimmedText)) {
dictionarySuccessCount++;
return dictResult;
}
// 4. 最终回退
fallbackCount++;
return getEnhancedFallback(trimmedText, sourceLang, targetLang);
}
/**
* 使ML Kit
*/
private String translateWithMLKit(String text, String sourceLang, String targetLang) {
final String[] result = {null};
final CountDownLatch latch = new CountDownLatch(1);
mlKitService.translateWithMLKit(text, sourceLang, targetLang,
new MLKitTranslationService.TranslationCallback() {
@Override
public void onSuccess(String translatedText) {
result[0] = translatedText;
latch.countDown();
}
@Override
public void onError(String errorMessage) {
result[0] = null;
latch.countDown();
}
});
try {
latch.await(5, TimeUnit.SECONDS);
return result[0];
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
}
}
/**
*
*/
private String enhancedDictionaryTranslate(String text, String sourceLang, String targetLang) {
String dictKey = generateDictionaryKey(sourceLang, targetLang);
String lowerText = text.toLowerCase();
// 1. 直接匹配
String directMatch = getDirectTranslation(lowerText, dictKey);
if (directMatch != null) {
return directMatch;
}
// 2. 短语匹配
String phraseMatch = findPhraseMatch(lowerText, dictKey);
if (phraseMatch != null) {
return phraseMatch;
}
// 3. 分词翻译
return wordBasedTranslate(text, dictKey, sourceLang, targetLang);
}
/**
*
*/
private String getDirectTranslation(String text, String dictKey) {
// 检查单词词典
Map<String, String> wordDict = wordDictionaries.get(dictKey);
if (wordDict != null) {
String translation = wordDict.get(text);
if (translation != null) {
return translation;
}
}
// 检查短语词典
Map<String, String> phraseDict = phraseDictionaries.get(dictKey);
if (phraseDict != null) {
return phraseDict.get(text);
}
return null;
}
/**
*
*/
private String findPhraseMatch(String text, String dictKey) {
Map<String, String> phraseDict = phraseDictionaries.get(dictKey);
if (phraseDict == null) return null;
// 精确匹配
String exactMatch = phraseDict.get(text);
if (exactMatch != null) return exactMatch;
// 包含匹配(文本包含词典中的短语)
for (Map.Entry<String, String> entry : phraseDict.entrySet()) {
if (text.contains(entry.getKey())) {
return entry.getValue();
}
}
return null;
}
/**
*
*/
private String wordBasedTranslate(String text, String dictKey,
String sourceLang, String targetLang) {
Map<String, String> wordDict = wordDictionaries.get(dictKey);
if (wordDict == null || wordDict.isEmpty()) {
return null;
}
// 分词处理
String[] words = text.split("\\s+");
StringBuilder result = new StringBuilder();
int translatedWords = 0;
for (String word : words) {
String cleanWord = word.toLowerCase().replaceAll("[^a-zA-Z\\u4e00-\\u9fff]", "");
if (cleanWord.isEmpty()) continue;
String translation = wordDict.get(cleanWord);
if (translation != null) {
result.append(translation).append(" ");
translatedWords++;
} else {
result.append(word).append(" ");
}
}
// 如果有翻译成功的单词,返回结果
if (translatedWords > 0) {
return result.toString().trim();
}
return null;
}
/**
*
*/
private String translateCommonPhrase(String text, String sourceLang, String targetLang) {
String lowerText = text.toLowerCase();
// 直接匹配
String directMatch = commonPhrases.get(lowerText);
if (directMatch != null) {
return directMatch;
}
// 模糊匹配(去除标点)
String cleanText = lowerText.replaceAll("[.,!?;:]", "");
return commonPhrases.get(cleanText);
}
/**
* 退
*/
private String getEnhancedFallback(String text, String sourceLang, String targetLang) {
// 尝试部分翻译
String partialTranslation = attemptPartialTranslation(text, sourceLang, targetLang);
if (partialTranslation != null && !partialTranslation.equals(text)) {
return "[部分翻译] " + partialTranslation;
}
// 最终回退
return String.format("[%s→%s] %s",
getLanguageCode(sourceLang),
getLanguageCode(targetLang),
text);
}
/**
*
*/
private String attemptPartialTranslation(String text, String sourceLang, String targetLang) {
String dictKey = generateDictionaryKey(sourceLang, targetLang);
Map<String, String> wordDict = wordDictionaries.get(dictKey);
if (wordDict == null) return text;
String[] words = text.split("\\s+");
StringBuilder result = new StringBuilder();
boolean hasTranslation = false;
for (String word : words) {
String cleanWord = word.toLowerCase().replaceAll("[^a-zA-Z\\u4e00-\\u9fff]", "");
String translation = wordDict.get(cleanWord);
if (translation != null && !translation.equals(cleanWord)) {
result.append(translation).append(" ");
hasTranslation = true;
} else {
result.append(word).append(" ");
}
}
return hasTranslation ? result.toString().trim() : text;
}
// ============ 工具方法 ============
private String generateDictionaryKey(String sourceLang, String targetLang) {
return sourceLang + "_" + targetLang;
}
private boolean isValidMLKitTranslation(String result, String original) {
return result != null &&
!result.trim().isEmpty() &&
!result.equals(original) &&
!result.contains("失败") &&
!result.contains("错误") &&
!result.contains("不支持");
}
private boolean isValidDictionaryTranslation(String result, String original) {
return result != null &&
!result.trim().isEmpty() &&
!result.equals(original) &&
result.length() > 0;
}
private String getLanguageCode(String language) {
switch (language) {
case "中文": return "ZH";
case "英语": return "EN";
case "日语": return "JA";
case "韩语": return "KO";
case "法语": return "FR";
default: return language.length() > 2 ? language.substring(0, 2).toUpperCase() : language;
}
}
/**
*
*/
public String getDictionaryStats() {
StringBuilder stats = new StringBuilder();
stats.append("词典统计:\n");
for (String key : wordDictionaries.keySet()) {
Map<String, String> wordDict = wordDictionaries.get(key);
Map<String, String> phraseDict = phraseDictionaries.get(key);
stats.append(String.format("• %s: 单词%d个, 短语%d个\n",
key, wordDict.size(), phraseDict.size()));
}
stats.append(String.format("常用短语: %d个\n", commonPhrases.size()));
stats.append(String.format("翻译统计: ML Kit(%d) 词典(%d) 回退(%d)",
mlKitSuccessCount, dictionarySuccessCount, fallbackCount));
return stats.toString();
}
/**
*
*/
public String searchDictionary(String query, String sourceLang, String targetLang) {
String dictKey = generateDictionaryKey(sourceLang, targetLang);
Map<String, String> wordDict = wordDictionaries.get(dictKey);
if (wordDict != null) {
String result = wordDict.get(query.toLowerCase());
if (result != null) {
return String.format("找到: %s -> %s", query, result);
}
}
return "未找到: " + query;
}
// ============ 公共方法 ============
/**
*
*/
public void translateAsync(String text, String sourceLang, String targetLang, TranslationCallback callback) {
new Thread(() -> {
String result = translate(text, sourceLang, targetLang);
if (isValidMLKitTranslation(result, text) || isValidDictionaryTranslation(result, text)) {
callback.onSuccess(result);
} else {
callback.onError(result);
}
}).start();
}
/**
* 线
*/
public void downloadModel(String sourceLang, String targetLang, DownloadCallback callback) {
if (mlKitService != null && mlKitAvailable) {
mlKitService.downloadModel(sourceLang, targetLang,
new MLKitTranslationService.DownloadCallback() {
@Override
public void onSuccess() {
Log.d(TAG, "✓ 离线模型下载成功");
callback.onSuccess();
}
@Override
public void onError(String errorMessage) {
Log.e(TAG, "✗ 离线模型下载失败: " + errorMessage);
callback.onError(errorMessage);
}
@Override
public void onProgress(int progress) {
callback.onProgress(progress);
}
});
} else {
callback.onError("ML Kit服务不可用");
}
}
/**
*
*/
public boolean isLanguagePairSupported(String sourceLang, String targetLang) {
// 检查ML Kit支持
if (mlKitAvailable && mlKitService != null) {
if (mlKitService.isOfflineTranslationSupported(sourceLang, targetLang)) {
return true;
}
}
// 检查离线词典支持
String dictKey = generateDictionaryKey(sourceLang, targetLang);
return wordDictionaries.containsKey(dictKey) || phraseDictionaries.containsKey(dictKey);
}
// ============ Getters ============
public boolean isMLKitAvailable() {
return mlKitAvailable;
}
public boolean isDictionaryEnhanced() {
return isDictionaryEnhanced;
}
public MLKitTranslationService getMLKitService() {
return mlKitService;
}
public String getSystemStatus() {
return String.format("ML Kit: %s, 增强词典: %s, 词条总数: %d",
mlKitAvailable ? "可用" : "不可用",
isDictionaryEnhanced ? "已加载" : "未加载",
getTotalDictionaryEntries());
}
private int getTotalDictionaryEntries() {
int total = commonPhrases.size();
for (Map<String, String> dict : wordDictionaries.values()) {
total += dict.size();
}
for (Map<String, String> dict : phraseDictionaries.values()) {
total += dict.size();
}
return total;
}
/**
* 使
*/
public String getTranslationEngineStats() {
StringBuilder stats = new StringBuilder();
stats.append("增强翻译引擎统计:\n");
if (mlKitAvailable) {
stats.append("• ML Kit: 可用");
if (mlKitService != null) {
stats.append(" (").append(mlKitService.getServiceStatus()).append(")");
}
stats.append("\n");
} else {
stats.append("• ML Kit: 不可用\n");
}
stats.append("• 增强词典: ").append(isDictionaryEnhanced ?
"已加载(" + getTotalDictionaryEntries() + "个词条)" : "未加载").append("\n");
stats.append("• 优先级: 常用短语 → ML Kit → 增强词典 → 回退翻译\n");
stats.append(String.format("• 使用统计: ML Kit(%d) 词典(%d) 回退(%d)",
mlKitSuccessCount, dictionarySuccessCount, fallbackCount));
return stats.toString();
}
/**
*
*/
public void resetStats() {
mlKitSuccessCount = 0;
dictionarySuccessCount = 0;
fallbackCount = 0;
}
}

@ -0,0 +1,42 @@
package com.translation.model;
public class GrammarExtension {
private String originalText;
private String extendedText;
private String extensionType; // "时态变化", "语态变化", "句式变化"等
private String explanation;
private String usageExample;
public GrammarExtension(String originalText, String extendedText,
String extensionType, String explanation) {
this.originalText = originalText;
this.extendedText = extendedText;
this.extensionType = extensionType;
this.explanation = explanation;
}
public GrammarExtension(String originalText, String extendedText,
String extensionType, String explanation, String usageExample) {
this.originalText = originalText;
this.extendedText = extendedText;
this.extensionType = extensionType;
this.explanation = explanation;
this.usageExample = usageExample;
}
// getters and setters
public String getOriginalText() { return originalText; }
public void setOriginalText(String originalText) { this.originalText = originalText; }
public String getExtendedText() { return extendedText; }
public void setExtendedText(String extendedText) { this.extendedText = extendedText; }
public String getExtensionType() { return extensionType; }
public void setExtensionType(String extensionType) { this.extensionType = extensionType; }
public String getExplanation() { return explanation; }
public void setExplanation(String explanation) { this.explanation = explanation; }
public String getUsageExample() { return usageExample; }
public void setUsageExample(String usageExample) { this.usageExample = usageExample; }
}

@ -0,0 +1,34 @@
package com.translation.model;
import java.util.List;
public class GrammarSuggestion {
private String originalText;
private String suggestedText;
private String explanation;
private String category;
private double confidence;
private String correctedText;
public GrammarSuggestion(String originalText, String suggestedText,
String explanation, String category, double confidence) {
this.originalText = originalText;
this.suggestedText = suggestedText;
this.explanation = explanation;
this.category = category;
this.confidence = confidence;
}
// Getters and Setters
public String getOriginalText() { return originalText; }
public String getSuggestedText() { return suggestedText; }
public String getExplanation() { return explanation; }
public String getCategory() { return category; }
public double getConfidence() { return confidence; }
public String getCorrectedText() {
return correctedText;
}
}

@ -0,0 +1,582 @@
package com.translation.model;
import android.content.Context;
import android.content.res.AssetManager;
import android.util.Log;
import com.translation.service.MLKitTranslationService;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class OfflineTranslationModel {
private static final String TAG = "OfflineTranslationModel";
private static OfflineTranslationModel instance;
private Context context;
// 主引擎:华为 ML Kit
private MLKitTranslationService mlKitService;
private boolean mlKitAvailable = false;
private boolean useMLKitAsPrimary = true;
// 备用引擎:离线词典
private Map<String, Map<String, String>> translationDictionaries;
private Map<String, String> commonPhrases;
private boolean isDictionaryLoaded = false;
// 协调器状态
private boolean isInitialized = false;
// 支持的语言对
private String[][] supportedLanguagePairs = {
{"中文", "英语"}, {"英语", "中文"},
{"中文", "日语"}, {"日语", "中文"},
{"中文", "韩语"}, {"韩语", "中文"},
{"中文", "法语"}, {"法语", "中文"},
{"中文", "德语"}, {"德语", "中文"},
{"中文", "西班牙语"}, {"西班牙语", "中文"},
{"中文", "俄语"}, {"俄语", "中文"},
{"英语", "日语"}, {"日语", "英语"},
{"英语", "韩语"}, {"韩语", "英语"},
{"英语", "法语"}, {"法语", "英语"},
{"英语", "德语"}, {"德语", "英语"},
{"英语", "西班牙语"}, {"西班牙语", "英语"},
{"英语", "俄语"}, {"俄语", "英语"}
};
// 回调接口
public interface TranslationCallback {
void onSuccess(String translatedText);
void onError(String errorMessage);
}
public interface DownloadCallback {
void onSuccess();
void onError(String errorMessage);
void onProgress(int progress);
}
private OfflineTranslationModel(Context context) {
this.context = context.getApplicationContext();
this.translationDictionaries = new HashMap<>();
this.commonPhrases = new HashMap<>();
initializeTranslationCoordinator();
}
public static synchronized OfflineTranslationModel getInstance(Context context) {
if (instance == null) {
instance = new OfflineTranslationModel(context);
}
return instance;
}
/**
*
*/
private void initializeTranslationCoordinator() {
Log.d(TAG, "初始化离线翻译协调器...");
// 并行初始化两个引擎
new Thread(() -> {
try {
// 1. 初始化ML Kit主引擎
initializeMLKitService();
// 2. 初始化离线词典(备用引擎)
initializeOfflineDictionary();
isInitialized = true;
Log.d(TAG, "✓ 离线翻译协调器初始化完成");
} catch (Exception e) {
Log.e(TAG, "✗ 离线翻译协调器初始化失败: " + e.getMessage());
}
}).start();
}
/**
* ML Kit
*/
private void initializeMLKitService() {
try {
mlKitService = new MLKitTranslationService(context);
mlKitAvailable = mlKitService.isInitialized();
if (mlKitAvailable) {
Log.d(TAG, "✓ ML Kit主引擎初始化成功");
} else {
Log.w(TAG, "⚠ ML Kit主引擎不可用将使用离线词典");
}
} catch (Exception e) {
Log.e(TAG, "✗ ML Kit主引擎初始化失败: " + e.getMessage());
mlKitAvailable = false;
}
}
private void initializeOfflineDictionary() {
try {
loadCommonPhrases();
// 中文到其他语言的词典
loadDictionaryFromAssets("dictionary_zh_en.json", "中文", "英语");
loadDictionaryFromAssets("dictionary_zh_ja.json", "中文", "日语");
loadDictionaryFromAssets("dictionary_zh_ko.json", "中文", "韩语");
loadDictionaryFromAssets("dictionary_zh_fr.json", "中文", "法语");
loadDictionaryFromAssets("dictionary_zh_de.json", "中文", "德语");
loadDictionaryFromAssets("dictionary_zh_es.json", "中文", "西班牙语");
loadDictionaryFromAssets("dictionary_zh_ru.json", "中文", "俄语");
// 其他语言到中文的词典(反向)
loadDictionaryFromAssets("dictionary_en_zh.json", "英语", "中文");
loadDictionaryFromAssets("dictionary_ja_zh.json", "日语", "中文");
loadDictionaryFromAssets("dictionary_ko_zh.json", "韩语", "中文");
loadDictionaryFromAssets("dictionary_fr_zh.json", "法语", "中文");
loadDictionaryFromAssets("dictionary_de_zh.json", "德语", "中文");
loadDictionaryFromAssets("dictionary_es_zh.json", "西班牙语", "中文");
loadDictionaryFromAssets("dictionary_ru_zh.json", "俄语", "中文");
isDictionaryLoaded = true;
Log.d(TAG, "✓ 离线词典备用引擎加载完成,词典数量: " + translationDictionaries.size());
} catch (Exception e) {
Log.e(TAG, "✗ 离线词典加载失败: " + e.getMessage());
isDictionaryLoaded = false;
}
}
/**
* 使ML Kit退
*/
public String translate(String text, String sourceLang, String targetLang) {
if (text == null || text.trim().isEmpty()) {
return "请输入要翻译的文本";
}
Log.d(TAG, String.format("开始协调翻译: %s -> %s, 文本: %s",
sourceLang, targetLang, text.substring(0, Math.min(20, text.length()))));
// 1. 优先使用ML Kit主引擎高优先级
if (useMLKitAsPrimary && mlKitAvailable && mlKitService != null) {
String mlKitResult = translateWithMLKit(text, sourceLang, targetLang);
if (isValidMLKitTranslation(mlKitResult)) {
Log.d(TAG, "✓ 使用ML Kit主引擎翻译成功");
return mlKitResult;
} else {
Log.w(TAG, "⚠ ML Kit翻译失败尝试离线词典");
}
}
// 2. 回退到离线词典备用引擎
if (isDictionaryLoaded) {
String dictionaryResult = translateWithDictionary(text, sourceLang, targetLang);
if (isValidDictionaryTranslation(dictionaryResult, text)) {
Log.d(TAG, "✓ 使用离线词典备用引擎翻译成功");
return dictionaryResult;
}
}
// 3. 最终回退方案
Log.w(TAG, "⚠ 所有翻译引擎均失败,使用最终回退");
return getFallbackTranslation(text, sourceLang, targetLang);
}
/**
* 使ML Kit
*/
private String translateWithMLKit(String text, String sourceLang, String targetLang) {
final String[] result = new String[1];
final CountDownLatch latch = new CountDownLatch(1);
mlKitService.translateWithMLKit(text, sourceLang, targetLang,
new MLKitTranslationService.TranslationCallback() {
@Override
public void onSuccess(String translatedText) {
result[0] = translatedText;
latch.countDown();
}
@Override
public void onError(String errorMessage) {
Log.w(TAG, "ML Kit翻译错误: " + errorMessage);
result[0] = null;
latch.countDown();
}
});
try {
boolean completed = latch.await(8, TimeUnit.SECONDS); // 缩短超时时间
if (!completed) {
Log.w(TAG, "ML Kit翻译超时");
}
return result[0];
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
}
}
/**
* ML Kit
*/
private boolean isValidMLKitTranslation(String result) {
if (result == null || result.trim().isEmpty()) {
return false;
}
// ML Kit特有的错误信息检查
return !result.contains("失败") &&
!result.contains("错误") &&
!result.contains("不支持") &&
!result.contains("未下载") &&
!result.contains("异常") &&
!result.startsWith("ML Kit");
}
/**
*
*/
private boolean isValidDictionaryTranslation(String result, String originalText) {
if (result == null || result.trim().isEmpty()) {
return false;
}
// 词典翻译可能包含未翻译的单词,只要不是完全失败就认为有效
return !result.equals(originalText) && // 结果与原文不同
!result.contains("失败") &&
!result.contains("错误");
}
/**
* 使线
*/
private String translateWithDictionary(String text, String sourceLang, String targetLang) {
// 1. 检查常用短语
String phraseTranslation = translateCommonPhrase(text, sourceLang, targetLang);
if (phraseTranslation != null) {
return phraseTranslation;
}
// 2. 检查词典
String dictKey = generateDictionaryKey(sourceLang, targetLang);
Map<String, String> dictionary = translationDictionaries.get(dictKey);
if (dictionary != null && !dictionary.isEmpty()) {
// 简单词典查找
String translation = dictionary.get(text.toLowerCase());
if (translation != null) {
return translation;
}
// 分词翻译
return translateWithDictionaryLogic(text, dictionary, sourceLang, targetLang);
}
return null;
}
/**
*
*/
private boolean isValidTranslation(String result) {
if (result == null || result.trim().isEmpty()) {
return false;
}
// 排除错误信息和回退文本
return !result.contains("失败") &&
!result.contains("错误") &&
!result.startsWith("[离线]") &&
!result.contains("不支持") &&
!result.contains("未翻译");
}
/**
* 退
*/
private String getFallbackTranslation(String text, String sourceLang, String targetLang) {
// 简单的回退:显示语言对信息
return String.format("[%s→%s] %s",
getLanguageCode(sourceLang),
getLanguageCode(targetLang),
text);
}
/**
* 线
*/
public void downloadModel(String sourceLang, String targetLang, DownloadCallback callback) {
if (mlKitService != null && mlKitAvailable) {
mlKitService.downloadModel(sourceLang, targetLang,
new MLKitTranslationService.DownloadCallback() {
@Override
public void onSuccess() {
Log.d(TAG, "✓ 离线模型下载成功");
callback.onSuccess();
}
@Override
public void onError(String errorMessage) {
Log.e(TAG, "✗ 离线模型下载失败: " + errorMessage);
callback.onError(errorMessage);
}
@Override
public void onProgress(int progress) {
callback.onProgress(progress);
}
});
} else {
callback.onError("ML Kit服务不可用");
}
}
/**
*
*/
public boolean isLanguagePairSupported(String sourceLang, String targetLang) {
// 检查ML Kit支持
if (mlKitAvailable && mlKitService != null) {
if (mlKitService.isOfflineTranslationSupported(sourceLang, targetLang)) {
return true;
}
}
// 检查离线词典支持
for (String[] pair : supportedLanguagePairs) {
if (pair[0].equals(sourceLang) && pair[1].equals(targetLang)) {
return true;
}
}
return false;
}
/**
*
*/
public List<String> getSupportedTargetLanguages(String sourceLang) {
List<String> targetLangs = new ArrayList<>();
// 从ML Kit获取支持的语言
if (mlKitAvailable && mlKitService != null) {
String[] mlKitLangs = mlKitService.getSupportedLanguages();
for (String lang : mlKitLangs) {
if (!lang.equals(sourceLang) && !targetLangs.contains(lang)) {
targetLangs.add(lang);
}
}
}
// 从离线词典获取支持的语言
for (String[] pair : supportedLanguagePairs) {
if (pair[0].equals(sourceLang) && !targetLangs.contains(pair[1])) {
targetLangs.add(pair[1]);
}
}
return targetLangs;
}
/**
*
*/
public String getModelStatus() {
StringBuilder status = new StringBuilder();
status.append("协调器状态: ").append(isInitialized ? "就绪" : "初始化中");
if (mlKitAvailable) {
status.append(" | ML Kit: 可用");
if (mlKitService != null) {
status.append(" (").append(mlKitService.getServiceStatus()).append(")");
}
} else {
status.append(" | ML Kit: 不可用");
}
status.append(" | 离线词典: ").append(isDictionaryLoaded ?
"已加载(" + translationDictionaries.size() + "个词典)" : "未加载");
status.append(" | 支持语言对: ").append(supportedLanguagePairs.length);
return status.toString();
}
// ============ 离线词典相关方法 ============
private void loadCommonPhrases() {
// 现有短语
commonPhrases.put("hello", "你好");
commonPhrases.put("thank you", "谢谢");
commonPhrases.put("good morning", "早上好");
commonPhrases.put("good night", "晚安");
commonPhrases.put("how are you", "你好吗");
commonPhrases.put("i love you", "我爱你");
commonPhrases.put("sorry", "对不起");
commonPhrases.put("excuse me", "打扰一下");
// 新增多语言短语
commonPhrases.put("guten tag", "你好");
commonPhrases.put("danke schön", "非常感谢");
commonPhrases.put("buenos días", "早上好");
commonPhrases.put("gracias", "谢谢");
commonPhrases.put("bonjour", "你好");
commonPhrases.put("merci", "谢谢");
// 反向映射
commonPhrases.put("你好", "hello");
commonPhrases.put("谢谢", "thank you");
commonPhrases.put("早上好", "good morning");
commonPhrases.put("晚安", "good night");
commonPhrases.put("非常感谢", "thank you very much");
}
private String translateCommonPhrase(String text, String sourceLang, String targetLang) {
String key = text.toLowerCase().trim();
return commonPhrases.get(key);
}
private String generateDictionaryKey(String sourceLang, String targetLang) {
return sourceLang + "_" + targetLang;
}
private String translateWithDictionaryLogic(String text, Map<String, String> dictionary,
String sourceLang, String targetLang) {
String[] words = text.split("\\s+");
StringBuilder result = new StringBuilder();
for (String word : words) {
String translation = dictionary.get(word.toLowerCase());
if (translation != null) {
result.append(translation).append(" ");
} else {
result.append(word).append(" ");
}
}
return result.toString().trim();
}
private void loadDictionaryFromAssets(String fileName, String sourceLang, String targetLang) {
try {
AssetManager assetManager = context.getAssets();
InputStream inputStream = assetManager.open(fileName);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
}
JSONObject jsonObject = new JSONObject(stringBuilder.toString());
JSONArray entries = jsonObject.getJSONArray("entries");
Map<String, String> dictionary = new HashMap<>();
for (int i = 0; i < entries.length(); i++) {
JSONObject entry = entries.getJSONObject(i);
String key = entry.getString("source");
String value = entry.getString("target");
dictionary.put(key.toLowerCase(), value);
}
String dictKey = generateDictionaryKey(sourceLang, targetLang);
translationDictionaries.put(dictKey, dictionary);
Log.d(TAG, "加载词典成功: " + fileName + ", 词条数: " + dictionary.size());
} catch (IOException | JSONException e) {
Log.w(TAG, "加载词典失败: " + fileName + ", 错误: " + e.getMessage());
}
}
private String getLanguageCode(String language) {
switch (language) {
case "中文": return "ZH";
case "英语": return "EN";
case "日语": return "JA";
case "韩语": return "KO";
case "法语": return "FR";
case "德语": return "DE";
case "西班牙语": return "ES";
case "俄语": return "RU";
case "葡萄牙语": return "PT";
case "意大利语": return "IT";
default: return "UN";
}
}
/**
* -
*/
public void translateAsync(String text, String sourceLang, String targetLang, TranslationCallback callback) {
new Thread(() -> {
String result = translate(text, sourceLang, targetLang);
if (isValidMLKitTranslation(result) || isValidDictionaryTranslation(result, text)) {
callback.onSuccess(result);
} else {
callback.onError(result);
}
}).start();
}
/**
* 使
*/
public String getTranslationEngineStats() {
StringBuilder stats = new StringBuilder();
stats.append("翻译引擎统计:\n");
if (mlKitAvailable) {
stats.append("• ML Kit: 可用");
if (mlKitService != null) {
stats.append(" (").append(mlKitService.getServiceStatus()).append(")");
}
stats.append("\n");
} else {
stats.append("• ML Kit: 不可用\n");
}
stats.append("• 离线词典: ").append(isDictionaryLoaded ?
"已加载(" + translationDictionaries.size() + "个词典)" : "未加载").append("\n");
stats.append("• 优先级: ML Kit → 离线词典");
return stats.toString();
}
// ============ Getters ============
public boolean isModelLoaded() {
return isInitialized;
}
public boolean isMLKitAvailable() {
return mlKitAvailable;
}
public boolean isDictionaryLoaded() {
return isDictionaryLoaded;
}
public void setUseMLKitAsPrimary(boolean useMLKitAsPrimary) {
this.useMLKitAsPrimary = useMLKitAsPrimary;
}
public MLKitTranslationService getMLKitService() {
return mlKitService;
}
}

@ -0,0 +1,43 @@
package com.translation.model;
public class Tag {
private int id;
private String name;
private String color;
private int recordCount;
// 主要构造函数
public Tag(int id, String name, int recordCount) {
this.id = id;
this.name = name;
this.recordCount = recordCount;
this.color = generateDefaultColor(id); // 根据ID生成默认颜色
}
// 可选:带颜色参数的构造函数
public Tag(int id, String name, String color, int recordCount) {
this.id = id;
this.name = name;
this.color = color;
this.recordCount = recordCount;
}
// 根据ID生成默认颜色
private String generateDefaultColor(int id) {
String[] colors = {"#FF5733", "#33FF57", "#3357FF", "#F333FF", "#FF33F3", "#33FFF3"};
return colors[id % colors.length];
}
// Getter 和 Setter 方法
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getColor() { return color; }
public void setColor(String color) { this.color = color; }
public int getRecordCount() { return recordCount; }
public void setRecordCount(int recordCount) { this.recordCount = recordCount; }
}

@ -0,0 +1,47 @@
package com.translation.model;
import java.util.List;
public class TranslationRecord {
private int id;
private String sourceText;
private String targetText;
private String sourceLang;
private String targetLang;
private String timestamp;
private List<String> tags;
public TranslationRecord(int id, String sourceText, String targetText,
String sourceLang, String targetLang, String timestamp,
List<String> tags) {
this.id = id;
this.sourceText = sourceText;
this.targetText = targetText;
this.sourceLang = sourceLang;
this.targetLang = targetLang;
this.timestamp = timestamp;
this.tags = tags;
}
// Getter 和 Setter 方法
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getSourceText() { return sourceText; }
public void setSourceText(String sourceText) { this.sourceText = sourceText; }
public String getTargetText() { return targetText; }
public void setTargetText(String targetText) { this.targetText = targetText; }
public String getSourceLang() { return sourceLang; }
public void setSourceLang(String sourceLang) { this.sourceLang = sourceLang; }
public String getTargetLang() { return targetLang; }
public void setTargetLang(String targetLang) { this.targetLang = targetLang; }
public String getTimestamp() { return timestamp; }
public void setTimestamp(String timestamp) { this.timestamp = timestamp; }
public List<String> getTags() { return tags; }
public void setTags(List<String> tags) { this.tags = tags; }
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save