Skip to content

Instantly share code, notes, and snippets.

@abjerner
Last active April 21, 2023 13:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save abjerner/28f734fd5300623c8fc43457b74bda07 to your computer and use it in GitHub Desktop.
Save abjerner/28f734fd5300623c8fc43457b74bda07 to your computer and use it in GitHub Desktop.
@using UmbracoTen
@inject MyLocalizationService LocalizationService
<ul class="alphalist-results-index">
@foreach (var letter in LocalizationService.GetAlphabet()) {
<li class="alphalist-results-item __active"><a href="/" title="@letter">@letter</a></li>
}
</ul>

Tips related to Create a multilingual a to z list in C#

When ever I'm doing something with localization, I create a service class to wrap the different logic. This could be getting labels from Umbraco's dictionary according to a given culture, or as here, getting the localized alphabet. I can then register it with my dependency injection container - eg. as a singleton.

A benefit from this approach opposed to a static class is that I can extend the class, and override some of it's methods. If the class grows in complexity, I could also consider having it backed by an interface. This could make testing and mocking it easier.

When needing the logic in a Razor view, the service can be injected like @inject MyLocalizationService LocalizationService - or in a similar way in C# classes.

When working with the service in a Razor view, it's probably unlikely that we'd need to specify another culture than the culture of the current thread, so I've added a method overload for both the GetAlphabet() and the GetFirstLetter() methods respectively. This way we can call the parameterless method without specifying a culture - but we still have the option to specify one via the method overload if we need to.

Compared to my example on Our, I've also changed the output type from string[] to IReadOnlyList<string> (string[] implements IReadOnlyList<string>). Arrays are mutable as you can change each item of the array, whereas IReadOnlyList<string> is immutable - unless you cast it back to string[].

I also relalized that I missed W in the English alphabet, so I've fixed that as well 😁

using System.Globalization;
namespace UmbracoTen {
/// <summary>
/// Class to handle various tasks related to localization.
/// </summary>
public class MyLocalizationService {
public static readonly IReadOnlyList<string> DanishAlphabet = new [] {
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "X", "Y", "Z", "Æ", "Ø", "Å"
};
public static readonly IReadOnlyList<string> EnglishAlphabet = new [] {
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "X", "Y", "Z"
};
public static readonly IReadOnlyList<string> WelshAlphabet = new [] {
"A", "B", "C", "CH", "D", "DD", "E", "F", "FF", "G", "NG", "H", "I", "J", "L", "LL", "M", "N", "O", "P", "PH", "R", "RH", "S", "T", "TH", "U", "W", "Y"
};
/// <summary>
/// Returns an array representing each character in the alphabet of the current culture.
/// </summary>
/// <returns>A string array representing the alphabet.</returns>
public virtual IReadOnlyList<string> GetAlphabet() {
return GetAlphabet(CultureInfo.CurrentCulture);
}
/// <summary>
/// Returns an array representing each character in the alphabet of the specified <paramref name="culture"/>.
/// </summary>
/// <param name="culture">The culture to be used.</param>
/// <returns>A string array representing the alphabet.</returns>
public virtual IReadOnlyList<string> GetAlphabet(CultureInfo culture) {
return culture.TwoLetterISOLanguageName switch {
"da" => DanishAlphabet,
"cy" => WelshAlphabet,
_ => EnglishAlphabet
};
}
/// <summary>
/// Returns the first character of the specified value, according to the current culture.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>A string represeting the first character.</returns>
public virtual string GetFirstLetter(string value) {
return GetFirstLetter(value, CultureInfo.CurrentCulture);
}
/// <summary>
/// Returns the first character of the specified value, according to the the specified <paramref name="culture"/>.
/// </summary>
/// <param name="value">The value.</param>
/// <param name="culture">The culture to be used.</param>
/// <returns>A string represeting the first character.</returns>
public virtual string GetFirstLetter(string value, CultureInfo culture) {
if (value.Length == 0) throw new Exception("Computer says no!");
value = value.ToLowerInvariant();
if (value.Length == 1) return value[..1];
if (culture.TwoLetterISOLanguageName == "cy") {
if (value[0] == 'c' && value[1] == 'h') return "ch";
if (value[0] == 'd' && value[1] == 'd') return "dd";
if (value[0] == 'f' && value[1] == 'f') return "ff";
if (value[0] == 'n' && value[1] == 'g') return "ng";
if (value[0] == 'l' && value[1] == 'l') return "ll";
if (value[0] == 'p' && value[1] == 'h') return "ph";
if (value[0] == 'r' && value[1] == 'h') return "rh";
if (value[0] == 't' && value[1] == 'h') return "th";
}
return value[..1];
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment