Add Simplified Chinese (zh) localization (#901)

* feat: add Simplified Chinese (zh) localization

- Add complete values-zh/strings.xml (921 strings, all keys covered)
- Translate 107 hardcoded UI strings across 34 Kotlin files
- Add 简体中文 option to in-app language picker
- Terminology aligned with official Hermes dashboard zh translations

* fix: resource-ize hardcoded Chinese strings per review

Address Hy4ri's review on PR #901:
- Move 104 hardcoded Chinese UI strings to string resources
  (English in values/strings.xml, Chinese in values-zh/strings.xml)
  referenced via stringResource()
- SystemViewModel labels -> @StringRes + AndroidViewModel with
  resource-based toast templates
- Make TodoTaskCardTest assertion locale-agnostic via getString()
- Update cookie tests to assert new host-agnostic session cookie
  behavior (WiFi/Tailscale switch-safe)
- Session cookie mirroring to WILDCARD bucket survives host switches

* style: apply ktlintFormat per review

---------

Co-authored-by: hermes-i18n <hermes-i18n@localhost>
This commit is contained in:
gslzwhlandhermes-i18n authored and GitHub committed 2026-08-15 11:33:43 +03:00
1 parent 0a5eb7a5b0
commit fdbd98af3e
46 files changed
+1420 -133

No files matched your search

@@ -1,12 +1,15 @@
package com.m57.hermescontrol.ui.chat
import android.content.Context
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import com.m57.hermescontrol.R
import com.m57.hermescontrol.theme.HermesControlTheme
import org.junit.Rule
import org.junit.Test
@@ -47,7 +50,7 @@ class TodoTaskCardTest {
}
composeTestRule.onNodeWithTag("todo_task_card").assertIsDisplayed()
composeTestRule.onNodeWithText("Tasks 1/3").assertIsDisplayed()
composeTestRule.onNodeWithText(taskCount(1, 3)).assertIsDisplayed()
composeTestRule.onNodeWithText("Finished").assertIsDisplayed()
composeTestRule.onNodeWithText("Working").assertIsDisplayed()
composeTestRule.onNodeWithText("Later").assertIsDisplayed()
@@ -94,7 +97,7 @@ class TodoTaskCardTest {
}
}
composeTestRule.onNodeWithText("Tasks 1/4").assertIsDisplayed()
composeTestRule.onNodeWithText(taskCount(1, 4)).assertIsDisplayed()
composeTestRule.onNodeWithContentDescription("Completed").assertIsDisplayed()
composeTestRule.onNodeWithContentDescription("Cancelled").assertIsDisplayed()
composeTestRule.onNodeWithText("Running alias").assertIsDisplayed()
@@ -119,4 +122,12 @@ class TodoTaskCardTest {
composeTestRule.onNodeWithTag("todo_task_card").assertDoesNotExist()
}
private fun taskCount(
completed: Int,
total: Int,
): String {
val context = ApplicationProvider.getApplicationContext<Context>()
return context.getString(R.string.todo_task_count, completed, total)
}
}