Skip to content

fix: localize runtime-generated UI text (5/3) - #6049

Open
eliotcougar wants to merge 2 commits into
2dust:masterfrom
eliotcougar:codex/issue-6005-runtime-localization
Open

fix: localize runtime-generated UI text (5/3)#6049
eliotcougar wants to merge 2 commits into
2dust:masterfrom
eliotcougar:codex/issue-6005-runtime-localization

Conversation

@eliotcougar

@eliotcougar eliotcougar commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Context and series

Follow-up to #6005.

This is the extracted part 5 of 3 in the localization series. It contains the runtime-code changes that were still bundled into the previous combined Part 3 draft in #6044, which itself was extracted from the original localization audit in #6021.

This branch is intentionally based on master, with no commits copied from Parts 3 or 4. It is designed to follow those PRs in the series.

Why runtime localization needs a separate boundary

Some text cannot be corrected by editing strings.xml alone. Connection tests, profile delays, exceptions, and retained main-screen status were being converted into display strings before the final UI knew which app locale to use.

Formatting those values in a service or daemon path has two problems:

  1. that process or Context can resolve resources using the device language rather than the language selected in v2rayNG; and
  2. localized sentences can leak into Logcat, where stable technical diagnostics are more useful.

This PR therefore transports structured or semantic data through runtime layers and applies localization only at a presentation boundary.

1. Keep the connection-test core path locale-neutral

Producer: CoreServiceManager

  • Removes Android string-resource formatting from the current-server delay test.
  • Renames MSG_MEASURE_DELAY_SUCCESS to MSG_MEASURE_DELAY_RESULT, because the message now represents either success or failure.
  • Sends a serializable ConnectionTestResult instead of a finished UI sentence.
  • Preserves the raw delay value and technical error detail.
  • Adds country code and IP address as separate nullable fields instead of building an English "(unknown) unknown" suffix in SpeedtestManager.

The DTO contains only locale-neutral values:

  • delayMillis
  • errorMessage
  • country
  • ipAddress

This keeps CoreServiceManager independent of presentation wording. The raw failure remains useful as a diagnostic, while the UI chooses the localized sentence and fallback text. ISO country codes and IP addresses are deliberately not translated.

Transport: MainRepository and MainServiceEvent

  • Deserializes ConnectionTestResult from the service broadcast.
  • Carries it through a typed MeasureDelayResult event.
  • Converts startup failure into semantic StateStartFailure state rather than displaying the service's raw exception text as a toast.

Consumer: MainViewModel

  • Formats success with connection_test_available and a separately localized delay value.
  • Formats failure with connection_test_error and a localized empty-message fallback.
  • Uses the localized unknown-value label only when the country or IP field is absent.
  • Leaves actual country codes, IP addresses, and technical error details unchanged.

The complete producer → transport → consumer chain was updated together so no old string payload remains on the connection-test path.

2. Represent retained main-screen status semantically

MainUiState previously retained already-formatted strings such as Connected, Testing, and connection-test results. A ViewModel survives activity recreation, so such strings could remain in the old language after an app-locale change.

This PR introduces MainStatus variants for:

  • disconnected;
  • connected;
  • testing;
  • test progress; and
  • connection-test results.

MainScreen asks MainViewModel to format the current semantic status when rendering. The selected app locale is therefore consulted at presentation time instead of being frozen into retained state.

3. Localize TCPing and real-delay units in profile rows

ServerAffiliationInfo.getTestDelayString() previously appended the literal English unit ms before the value reached Compose.

  • ServerAffiliationInfo and ServersCache now retain only the numeric millisecond value.
  • ServerListItem formats that value with stringResource(R.string.server_test_delay_value, ...).
  • The current-connection test uses the same resource, keeping the unit consistent between the main status and profile rows.

The unit resource is provided in all nine maintained locale catalogs.

4. Separate diagnostic exceptions from localized user failures

Two exception paths previously exposed platform or exception text directly to users:

  • update checking; and
  • sharing Logcat output.

Both paths now log the original exception, including its diagnostic detail and stack trace, while showing the stable localized toast_failure message in the UI. This avoids device-language/platform exception text in the interface without reducing Logcat usefulness.

Startup failures follow the same principle: the core/service logs the technical cause, while the main UI displays toast_services_failure.

5. Clarify code-dependent settings UI

Routing rule matching

The old comma-separated hint was repeated inside the domain, IP, and process fields and incorrectly suggested choosing only one field.

  • Displays the rule-combination explanation once above the matching fields.
  • States that every populated matching condition must be satisfied together (AND).
  • States that rules are checked from top to bottom and the first matching rule is applied.
  • Keeps a short comma-separated-entry hint inside the applicable fields.

The placement and wording now match how a RulesetItem is converted into one Xray routing rule.

Subscription proxy-chain endpoints

The labels Previous proxy config remarks and Next proxy config remarks described storage fields rather than their visible effect.

  • Renames them to Entry proxy and Exit proxy.
  • Adds reusable supporting text to FormDropdownField.
  • Explains below each field that the selected proxy is inserted before or after every profile in the subscription as that profile's entry or exit chain link.

The labels remain mapped to the existing prevProfile and nextProfile fields; no subscription data format or chain-building behavior changes.

Resource ownership and focus

The new or code-dependent resources are supplied in English, Arabic, Bangla, Bakhtiari, Persian, Russian, Vietnamese, Simplified Chinese, and Traditional Chinese.

This PR changes exactly 16 resource identifiers per locale:

  • four new presentation resources;
  • four existing code-dependent labels/messages; and
  • eight obsolete core_error_* resources removed after the core configuration path became resource-neutral.

The catalogs retain identical identifiers, order, physical row alignment, and format placeholders. These resource identifiers do not overlap the identifiers changed by #6047 or #6048.

Impact

  • Connection-test results are formatted in the selected app language at the UI boundary.
  • Main-screen status cannot retain a sentence from the previous locale.
  • TCPing and real-delay units follow the active locale.
  • Core/service paths carry stable data and diagnostics rather than UI prose.
  • User-facing failure toasts stay localized while Logcat retains the original exception.
  • Routing and subscription-chain settings describe their actual runtime behavior.

@eliotcougar
eliotcougar marked this pull request as ready for review August 9, 2026 12:28
@eliotcougar

Copy link
Copy Markdown
Contributor Author

@2dust Tell me if you want it to be split even further.

Keep connection-test and status data locale-neutral until the UI formats it, and localize delay units at their Compose presentation boundary.\n\nShow stable localized failures while retaining diagnostic exceptions in Logcat. Clarify routing rule matching and subscription entry/exit proxy behavior at the relevant UI call sites, and remove the now-unused core error resources.
@eliotcougar
eliotcougar force-pushed the codex/issue-6005-runtime-localization branch from ce16b09 to bcd57fb Compare August 10, 2026 08:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant