Skip to content

Commit b4bf855

Browse files
committed
Refactor docs and naming in LocalizationManager for clarity
- Rewrite and expand XML documentation for InvalidationKey and LocalizationManager, including detailed parameter and method descriptions. - Rename constructor parameter from db to dbContext and update all references for consistency. - Improve method summaries and remarks to clarify async behavior, cache invalidation, and distributed scenarios. - Enhance BuildCacheKey documentation for formatting and culture handling. - No functional changes; improves code readability and maintainability.
1 parent 656e3b4 commit b4bf855

2 files changed

Lines changed: 64 additions & 59 deletions

File tree

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
namespace TinyLocalization.Services;
22

33
/// <summary>
4-
/// Payload element used for resource-level invalidation: a pair containing a translation <see cref="Key"/>
5-
/// and the target <see cref="Culture"/>. Instances of this record are typically included in resource-level
6-
/// invalidation messages to indicate which specific keys and cultures should be evicted or refreshed by subscribers.
4+
/// Represents a unique key for invalidation, consisting of a key string and a culture identifier.
75
/// </summary>
8-
/// <param name="Key">The translation key within the resource to be invalidated.</param>
9-
/// <param name="Culture">The culture name (for example "en" or "en-US") whose cached entry should be invalidated.</param>
6+
/// <param name="Key">The unique identifier used for invalidation purposes.</param>
7+
/// <param name="Culture">The culture associated with the key, which may influence localization or regional settings.</param>
108
public record InvalidationKey(string Key, string Culture);

‎src/TinyLocalization/Services/LocalizationManager.cs‎

Lines changed: 61 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -8,58 +8,68 @@
88
namespace TinyLocalization.Services;
99

1010
/// <summary>
11-
/// Manager that modifies the translations database and invalidates associated FusionCache keys.
11+
/// Provides methods for managing localization resources, including adding, updating, removing, and invalidating
12+
/// translations across different cultures. Ensures consistency between the underlying database and the cache for
13+
/// localized content.
1214
/// </summary>
13-
/// <param name="db">The <see cref="LocalizationDbContext"/> used to access translations in the database.</param>
14-
/// <param name="fusionCache">The <see cref="IFusionCache"/> used for local caching of translations.</param>
15-
/// <param name="options">Options controlling localization behavior, including cache key prefix.</param>
16-
/// <param name="publisher">Optional publisher used to broadcast cache invalidations to other instances.</param>
17-
public class LocalizationManager(LocalizationDbContext db, IFusionCache fusionCache, DbLocalizationOptions options,
15+
/// <remarks>This class is designed for scenarios where localization data may be updated at runtime and must be
16+
/// kept consistent across multiple application instances. It provides asynchronous operations to ensure that changes to
17+
/// translations are reflected in both the database and the cache, and supports distributed cache invalidation when a
18+
/// publisher is supplied.</remarks>
19+
/// <param name="dbContext">The database context used to access and persist localization data.</param>
20+
/// <param name="fusionCache">The cache instance used to store and retrieve localization resources for improved performance.</param>
21+
/// <param name="options">The options that configure the behavior of the localization manager, such as cache key prefix settings.</param>
22+
/// <param name="publisher">An optional publisher used to broadcast cache invalidation messages to other application instances. If not provided,
23+
/// cache invalidation is performed only locally.</param>
24+
public class LocalizationManager(LocalizationDbContext dbContext, IFusionCache fusionCache, DbLocalizationOptions options,
1825
ICacheInvalidationPublisher? publisher = null) : ILocalizationManager
1926
{
2027
/// <summary>
21-
/// Builds the cache key used to store a translation in the cache.
28+
/// Generates a unique cache key that combines the specified resource identifier, key, and culture information.
2229
/// </summary>
23-
/// <param name="resource">The resource name the translation belongs to.</param>
24-
/// <param name="key">The translation key.</param>
25-
/// <param name="culture">
26-
/// The culture identifier for the translation. If <see cref="string.IsNullOrEmpty(string)"/> is true,
27-
/// an underscore ("_") segment is used to represent the empty culture in the key.
28-
/// </param>
29-
/// <returns>A string representing the full cache key for the given resource/key/culture combination.</returns>
30+
/// <remarks>Use this method to ensure that cache keys are consistently formatted and unique across
31+
/// different resources and cultures. This is particularly useful in localization scenarios where cache entries must
32+
/// be separated by culture.</remarks>
33+
/// <param name="resource">The resource identifier used to distinguish the cache entry. Cannot be null.</param>
34+
/// <param name="key">The unique key associated with the resource for cache retrieval. Cannot be null.</param>
35+
/// <param name="culture">The culture name used to differentiate cache entries for localization. If null or empty, a default segment is
36+
/// used.</param>
37+
/// <returns>A formatted string representing the complete cache key, including the cache key prefix, resource, key, and
38+
/// culture segment.</returns>
3039
private string BuildCacheKey(string resource, string key, string culture)
3140
{
3241
var cultureSegment = string.IsNullOrEmpty(culture) ? "_" : culture;
3342
return $"{options.CacheKeyPrefix}:{resource}:{key}:{cultureSegment}";
3443
}
3544

3645
/// <summary>
37-
/// Adds a new translation or updates an existing one in the database, then invalidates the corresponding cache entry.
46+
/// Adds a new translation or updates an existing translation asynchronously in the database for the specified
47+
/// resource, key, and culture.
3848
/// </summary>
39-
/// <param name="translation">The <see cref="Translation"/> entity to add or update.</param>
40-
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to observe while waiting for the task to complete.</param>
41-
/// <returns>A task that represents the asynchronous operation.</returns>
42-
/// <remarks>
43-
/// If a translation with the same resource, key and culture already exists it will be updated; otherwise a new entry
44-
/// will be added. After persisting changes it removes the matching FusionCache key locally and, when a publisher is
45-
/// provided, publishes a single-item invalidation to other instances.
46-
/// </remarks>
49+
/// <remarks>If a translation with the same resource, key, and culture already exists, its value is
50+
/// updated; otherwise, a new translation is added. After the operation, the local cache for the affected
51+
/// translation is invalidated, and an invalidation message is published to other instances if a publisher is
52+
/// available.</remarks>
53+
/// <param name="translation">The translation to add or update. The resource, key, and culture identify the translation entry; the value is
54+
/// stored or updated.</param>
55+
/// <param name="cancellationToken">A cancellation token that can be used to cancel the asynchronous operation.</param>
56+
/// <returns>A task that represents the asynchronous add or update operation.</returns>
4757
public async Task AddOrUpdateAsync(Translation translation, CancellationToken cancellationToken = default)
4858
{
49-
var existing = await db.Translations.FirstOrDefaultAsync(t
59+
var existing = await dbContext.Translations.FirstOrDefaultAsync(t
5060
=> t.Resource == translation.Resource && t.Key == translation.Key && t.Culture == translation.Culture, cancellationToken);
5161

5262
if (existing == null)
5363
{
54-
db.Translations.Add(translation);
64+
dbContext.Translations.Add(translation);
5565
}
5666
else
5767
{
5868
existing.Value = translation.Value;
59-
db.Translations.Update(existing);
69+
dbContext.Translations.Update(existing);
6070
}
6171

62-
await db.SaveChangesAsync(cancellationToken);
72+
await dbContext.SaveChangesAsync(cancellationToken);
6373

6474
// Invalidate cache for that exact resource/key/culture locally
6575
var cacheKey = BuildCacheKey(translation.Resource, translation.Key, translation.Culture);
@@ -73,32 +83,29 @@ public async Task AddOrUpdateAsync(Translation translation, CancellationToken ca
7383
}
7484

7585
/// <summary>
76-
/// Removes a translation for the specified resource/key/culture from the database and invalidates the cache.
86+
/// Removes a translation entry for the specified resource, key, and culture from the database asynchronously.
7787
/// </summary>
78-
/// <param name="resource">The resource name the translation belongs to.</param>
79-
/// <param name="key">The translation key to remove.</param>
80-
/// <param name="culture">The culture identifier of the translation to remove.</param>
81-
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to observe while waiting for the task to complete.</param>
82-
/// <returns>
83-
/// A task that returns <c>true</c> if the translation was found and removed; otherwise <c>false</c> when no matching
84-
/// translation exists.
85-
/// </returns>
86-
/// <remarks>
87-
/// After removing the translation and saving changes the method removes the corresponding FusionCache entry locally
88-
/// and, if a publisher is configured, publishes a single-item invalidation to other instances.
89-
/// </remarks>
88+
/// <remarks>This method also invalidates the local cache for the removed translation and publishes an
89+
/// invalidation notification if a publisher is available. If no matching translation entry is found, no changes are
90+
/// made.</remarks>
91+
/// <param name="resource">The name of the resource associated with the translation entry to remove. Cannot be null.</param>
92+
/// <param name="key">The key that identifies the specific translation entry to remove. Cannot be null.</param>
93+
/// <param name="culture">The culture code that specifies which translation to remove. Cannot be null.</param>
94+
/// <param name="cancellationToken">A cancellation token that can be used to cancel the asynchronous operation.</param>
95+
/// <returns>A task that represents the asynchronous operation. The task result is <see langword="true"/> if the translation
96+
/// entry was found and removed; otherwise, <see langword="false"/>.</returns>
9097
public async Task<bool> RemoveAsync(string resource, string key, string culture, CancellationToken cancellationToken = default)
9198
{
92-
var existing = await db.Translations.FirstOrDefaultAsync(t
99+
var existing = await dbContext.Translations.FirstOrDefaultAsync(t
93100
=> t.Resource == resource && t.Key == key && t.Culture == culture, cancellationToken);
94101

95102
if (existing == null)
96103
{
97104
return false;
98105
}
99106

100-
db.Translations.Remove(existing);
101-
await db.SaveChangesAsync(cancellationToken);
107+
dbContext.Translations.Remove(existing);
108+
await dbContext.SaveChangesAsync(cancellationToken);
102109

103110
// invalidate cache locally
104111
var cacheKey = BuildCacheKey(resource, key, culture);
@@ -114,20 +121,20 @@ public async Task<bool> RemoveAsync(string resource, string key, string culture,
114121
}
115122

116123
/// <summary>
117-
/// Invalidates all cached entries for a given resource across known cultures and keys.
124+
/// Asynchronously invalidates all cached entries for the specified resource across all known cultures.
118125
/// </summary>
119-
/// <param name="resource">The resource name whose cache entries should be invalidated.</param>
120-
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to observe while waiting for the task to complete.</param>
121-
/// <returns>A task that represents the asynchronous operation.</returns>
122-
/// <remarks>
123-
/// The method enumerates the distinct cultures and keys for the resource in the database, removes the corresponding
124-
/// FusionCache entries locally, and collects <see cref="InvalidationKey"/> instances to publish a resource-level
125-
/// invalidation to other instances when a publisher is configured.
126-
/// </remarks>
126+
/// <remarks>This method removes all cache entries associated with the specified resource for each culture
127+
/// present in the data store. If a publisher is available, a resource-level invalidation notification is published
128+
/// after the cache entries are removed. Use this method to ensure that changes to a resource are reflected across
129+
/// all cultures and that outdated translations are not served from the cache.</remarks>
130+
/// <param name="resource">The name of the resource to invalidate. This parameter cannot be null or empty.</param>
131+
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation. The default value is <see
132+
/// cref="CancellationToken.None"/>.</param>
133+
/// <returns>A task that represents the asynchronous operation of invalidating the resource.</returns>
127134
public async Task InvalidateResourceAsync(string resource, CancellationToken cancellationToken = default)
128135
{
129136
// enumerate known cultures for this resource and remove corresponding keys
130-
var cultures = await db.Translations
137+
var cultures = await dbContext.Translations
131138
.Where(t => t.Resource == resource)
132139
.Select(t => t.Culture)
133140
.Distinct()
@@ -138,7 +145,7 @@ public async Task InvalidateResourceAsync(string resource, CancellationToken can
138145
foreach (var culture in cultures)
139146
{
140147
// for each key too
141-
var keys = await db.Translations
148+
var keys = await dbContext.Translations
142149
.Where(t => t.Resource == resource && t.Culture == culture)
143150
.Select(t => t.Key)
144151
.Distinct()

0 commit comments

Comments
 (0)