Skip to content

Locale System Refactor#861

Open
neon-nyan wants to merge 16 commits intomainfrom
refactor-locale-system
Open

Locale System Refactor#861
neon-nyan wants to merge 16 commits intomainfrom
refactor-locale-system

Conversation

@neon-nyan
Copy link
Member

Main Goal

The localization has been rewritten entirely to enable couple of improvements for easier UI element maintainability and binding process. List of improvements in this PR as follows:

[New] Switching to source-generated JSON -> Class mapper & deserializer.

Previously, developer should map the property inside of the source-code to represents entries inside of the locale .json file. Thanks to source-generated mapper, the property will be populated and generated automatically each time new entries have been added to the .json file.

[New] Add binding support to the Locale object.

This enables each UI Elements that binds their represented Locale property, to be able to have its text updated while a locale is being changed to another language without the needs of manual binding update.

PR Status :

  • Overall Status : Done
  • Commits : Done
  • Synced to base (Collapse:main) : Yes
  • Build status : OK
  • Crashing : No
  • Bug found caused by PR : Unknown

Templates

Changelog Prefixes
  **[New]**
  **[Imp]**
  **[Fix]**
  **[Loc]**
  **[Doc]**

@neon-nyan neon-nyan requested a review from a team March 15, 2026 06:32
@neon-nyan neon-nyan self-assigned this Mar 15, 2026
@neon-nyan neon-nyan added Enhancement New feature or request Area: Translation Issue labeled for Translation that need to be working on Area: UI/UX Issue labeled for User Interface/eXperience related issue Priority: High Size: Large labels Mar 15, 2026
Comment on lines +90 to +100
return 0;
}

// Get first value reference
TKey? firstKey = dict.Keys.FirstOrDefault();
if (firstKey == null)
{
throw new InvalidOperationException();
}
ref TValue firstRef = ref CollectionsMarshal.GetValueRefOrNullRef(dict, firstKey);
if (Unsafe.IsNullRef(ref firstRef))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The GetValueIndexFromKey method uses unsafe pointer arithmetic to find a dictionary value's index, which is unreliable and not guaranteed to work by the .NET runtime.
Severity: CRITICAL

Suggested Fix

Replace the unsafe pointer arithmetic in GetValueIndexFromKey. A reliable approach would be to convert the dictionary's keys or values to a list and use the IndexOf() method to find the correct index. For example: dict.Keys.ToList().IndexOf(key).

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location:
CollapseLauncher/Classes/Helper/Metadata/LauncherMetadataHelper.GameTitleAndRegion.cs#L83-L100

Potential issue: The `GetValueIndexFromKey` method calculates a dictionary value's index
using unsafe pointer arithmetic. It computes the byte offset between the first value's
reference and the target value's reference, then divides by a hardcoded or calculated
size. This approach incorrectly assumes that a .NET `Dictionary<TKey, TValue>` stores
its values in a contiguous memory block ordered by insertion, which is not a guaranteed
contract. This faulty index is then used to select an item in a UI combo box, leading to
the wrong game region being displayed and potentially used, and also causes unnecessary
re-initialization of Discord's Rich Presence feature due to incorrect equality checks.

Did we get this right? 👍 / 👎 to inform future reviews.


// Initialize and clear the stamp dictionary
LauncherMetadataStampDictionary ??= new Dictionary<string, Stamp>();
LauncherMetadataStampDictionary.Clear();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The static list LauncherMetadataStamp is not cleared on re-initialization, leading to duplicate entries and a crash from an ArgumentException when populating a dictionary.
Severity: HIGH

Suggested Fix

Add LauncherMetadataStamp.Clear() at the beginning of the InitializeStamp method, before LauncherMetadataStampDictionary.Clear(), to ensure the list is empty before new stamp data is added. This will prevent the accumulation of duplicate entries across multiple initializations.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: CollapseLauncher/Classes/Helper/Metadata/LauncherMetadataHelper.cs#L242

Potential issue: The `InitializeStamp` method is called during application
initialization. It clears `LauncherMetadataStampDictionary` but fails to clear the
underlying `LauncherMetadataStamp` list before adding new items with `AddRange`. If
`Initialize` is called more than once during the application's lifecycle (e.g., during
OOBE setup or on config re-initialization), the `LauncherMetadataStamp` list accumulates
duplicate entries. The subsequent logic attempts to add these items to the dictionary
using `dict.Add()`, which will throw an `ArgumentException` upon encountering a
duplicate key, causing the application to crash.

Did we get this right? 👍 / 👎 to inform future reviews.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: Translation Issue labeled for Translation that need to be working on Area: UI/UX Issue labeled for User Interface/eXperience related issue Enhancement New feature or request Priority: High Size: Large

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant