在不了解文化的情况下将月份名称从一种语言转换为另一种语言?
Convert month name from one language to another without knowing the Culture?
如何在不知道“agosto”是西班牙语还是意大利语的情况下将带有月份名称(如“agosto”)的字符串转换为英文翻译“August”?
我知道我用
得到了西班牙语中第 8 个月的月份名称
Dim SpanishMonthName as String = Globalization.CultureInfo.GetCultureInfo("ES").DateTimeFormat.GetMonthName(8)
但是我怎样才能将字符串“August”(英语中的第 8 个月名称)作为西班牙语或意大利语月份名称“agosto”的翻译?
在各种 CultureInfo
中有月份名称(参见 someCulture.DateTimeFormat.MonthNames
),因此您可以:
var italian = CultureInfo.GetCultureInfo("it-IT");
var spanish = CultureInfo.GetCultureInfo("es-ES");
var english = CultureInfo.GetCultureInfo("en-US");
string month = "agosto";
var italianMonthNames = italian.DateTimeFormat.MonthNames;
var spanishMonthNames = spanish.DateTimeFormat.MonthNames;
int ix = Array.FindIndex(italianMonthNames, x => StringComparer.OrdinalIgnoreCase.Equals(x, month));
if (ix == -1)
{
ix = Array.FindIndex(spanishMonthNames, x => StringComparer.OrdinalIgnoreCase.Equals(x, month));
}
// ix is 0 based, while months are 1 based
string englishMonth = ix != -1 ? english.DateTimeFormat.GetMonthName(ix + 1) : null;
您甚至可以尝试将一点委托给 .NET DateTime.ParseExact
:
var italian = CultureInfo.GetCultureInfo("it-IT");
var spanish = CultureInfo.GetCultureInfo("es-ES");
var english = CultureInfo.GetCultureInfo("en-US");
string month = "agosto";
string englishMonth = null;
DateTime dt;
if (DateTime.TryParseExact(month, "MMMM", italian, 0, out dt) || DateTime.TryParseExact(month, "MMMM", spanish, 0, out dt))
{
englishMonth = dt.ToString("MMMM", english);
}
一般来说,至少有一个月份在两种语言中具有不同的含义:listopad(十月或十一月,参见here)。完整列表是 Hlakola、listopad、Mopitlo、Nhlangula、Nyakanga、Phupu
使用 Dictionary<>
收集月份名称的第一个版本:
public class MonthNameFinder
{
private readonly IReadOnlyDictionary<string, int> MonthToNumber;
public MonthNameFinder(params string[] cultures)
{
MonthToNumber = BuildDictionary(cultures.Select(x => CultureInfo.GetCultureInfo(x)));
}
public MonthNameFinder(params CultureInfo[] cultureInfos)
{
MonthToNumber = BuildDictionary(cultureInfos);
}
public MonthNameFinder(CultureTypes cultureTypes = CultureTypes.AllCultures)
{
MonthToNumber = BuildDictionary(CultureInfo.GetCultures(cultureTypes));
}
private static IReadOnlyDictionary<string, int> BuildDictionary(IEnumerable<CultureInfo> cultureInfos)
{
// Note that the comparer will always be wrong, sadly. Each culture has its comparer
var dict = new Dictionary<string, int>(StringComparer.InvariantCultureIgnoreCase);
foreach (var culture in cultureInfos)
{
var monthNames = culture.DateTimeFormat.MonthNames;
for (int i = 0; i < monthNames.Length; i++)
{
string monthName = monthNames[i];
int other;
if (!dict.TryGetValue(monthName, out other))
{
dict[monthName] = i + 1;
}
else if (other != i + 1)
{
Debug.WriteLine($"Repeated month {monthName}: {i + 1} in {culture.Name} ({culture.DisplayName})");
}
}
}
return dict;
}
public int? GetMonthNumber(string monthName)
{
int monthNumber;
if (MonthToNumber.TryGetValue(monthName, out monthNumber))
{
return monthNumber;
}
return null;
}
}
像这样使用它:
var mnf = new MonthNameFinder();
int? n = mnf.GetMonthNumber("agosto");
if (n != null)
{
string name = new DateTime(1, n.Value, 1).ToString("MMMM", CultureInfo.GetCultureInfo("en-US"));
}
(请注意,您应该缓存 mnf
...构建起来可能相当昂贵)
嗯...我不喜欢...我有点 OC...我知道月份名称中存在一些冲突这一简单事实困扰着我。
这是第二个版本,使用 ILookup<>
甚至保存 CultureName
,这样就可以发现月份名称的语言。这
GetMonthNumbers(monthName)
现在 returns 一个 (int MonthNumber, string CultureName)[]
,一个匿名值类型的数组。可以明明拿第一个开心的过日子,也可以查一下有没有多个不同的MonthNumber
public class MonthNameFinder
{
private readonly ILookup<string, (int MonthNumber, string CultureName)> MonthToNumber;
public MonthNameFinder(params string[] cultures)
{
MonthToNumber = BuildLookup(cultures.Select(x => CultureInfo.GetCultureInfo(x)));
}
public MonthNameFinder(params CultureInfo[] cultureInfos)
{
MonthToNumber = BuildLookup(cultureInfos);
}
public MonthNameFinder(CultureTypes cultureTypes = CultureTypes.AllCultures)
{
MonthToNumber = BuildLookup(CultureInfo.GetCultures(cultureTypes));
}
private static ILookup<string, (int MonthNumber, string CultureName)> BuildLookup(IEnumerable<CultureInfo> cultureInfos)
{
// Note that the comparer will always be wrong, sadly. Each culture has its comparer
var lst = new List<(string Name, int MonthNumber, string CultureName)>();
foreach (var culture in cultureInfos)
{
var monthNames = culture.DateTimeFormat.MonthNames;
for (int i = 0; i < monthNames.Length; i++)
{
string monthName = monthNames[i];
lst.Add((monthName, i + 1, culture.Name));
}
}
return lst.OrderBy(x => x.Name)
.ThenBy(x => x.MonthNumber)
.ToLookup(x => x.Name, x => (x.MonthNumber, x.CultureName), StringComparer.InvariantCultureIgnoreCase);
}
public (int MonthNumber, string CultureName)[] GetMonthNumbers(string monthName)
{
return MonthToNumber[monthName].ToArray();
}
}
像这样使用它:
// This is an array of (MonthNumber, CultureName)
var mnf = new MonthNameFinder();
var numbers = mnf.GetMonthNumbers("agosto");
if (numbers.Length != 0)
{
string monthName = new DateTime(1, numbers[0].MonthNumber, 1).ToString("MMMM", CultureInfo.GetCultureInfo("en-US"));
}
(即使在这里你也应该缓存 mnf
...构建起来可能相当昂贵)
请注意,有许多相似的文化,因此 numbers
会很大(例如,仅意大利语就有 5 种文化,搜索 agosto 返回52 种不同的文化与月份 agosto.
如何在不知道“agosto”是西班牙语还是意大利语的情况下将带有月份名称(如“agosto”)的字符串转换为英文翻译“August”?
我知道我用
得到了西班牙语中第 8 个月的月份名称Dim SpanishMonthName as String = Globalization.CultureInfo.GetCultureInfo("ES").DateTimeFormat.GetMonthName(8)
但是我怎样才能将字符串“August”(英语中的第 8 个月名称)作为西班牙语或意大利语月份名称“agosto”的翻译?
在各种 CultureInfo
中有月份名称(参见 someCulture.DateTimeFormat.MonthNames
),因此您可以:
var italian = CultureInfo.GetCultureInfo("it-IT");
var spanish = CultureInfo.GetCultureInfo("es-ES");
var english = CultureInfo.GetCultureInfo("en-US");
string month = "agosto";
var italianMonthNames = italian.DateTimeFormat.MonthNames;
var spanishMonthNames = spanish.DateTimeFormat.MonthNames;
int ix = Array.FindIndex(italianMonthNames, x => StringComparer.OrdinalIgnoreCase.Equals(x, month));
if (ix == -1)
{
ix = Array.FindIndex(spanishMonthNames, x => StringComparer.OrdinalIgnoreCase.Equals(x, month));
}
// ix is 0 based, while months are 1 based
string englishMonth = ix != -1 ? english.DateTimeFormat.GetMonthName(ix + 1) : null;
您甚至可以尝试将一点委托给 .NET DateTime.ParseExact
:
var italian = CultureInfo.GetCultureInfo("it-IT");
var spanish = CultureInfo.GetCultureInfo("es-ES");
var english = CultureInfo.GetCultureInfo("en-US");
string month = "agosto";
string englishMonth = null;
DateTime dt;
if (DateTime.TryParseExact(month, "MMMM", italian, 0, out dt) || DateTime.TryParseExact(month, "MMMM", spanish, 0, out dt))
{
englishMonth = dt.ToString("MMMM", english);
}
一般来说,至少有一个月份在两种语言中具有不同的含义:listopad(十月或十一月,参见here)。完整列表是 Hlakola、listopad、Mopitlo、Nhlangula、Nyakanga、Phupu
使用 Dictionary<>
收集月份名称的第一个版本:
public class MonthNameFinder
{
private readonly IReadOnlyDictionary<string, int> MonthToNumber;
public MonthNameFinder(params string[] cultures)
{
MonthToNumber = BuildDictionary(cultures.Select(x => CultureInfo.GetCultureInfo(x)));
}
public MonthNameFinder(params CultureInfo[] cultureInfos)
{
MonthToNumber = BuildDictionary(cultureInfos);
}
public MonthNameFinder(CultureTypes cultureTypes = CultureTypes.AllCultures)
{
MonthToNumber = BuildDictionary(CultureInfo.GetCultures(cultureTypes));
}
private static IReadOnlyDictionary<string, int> BuildDictionary(IEnumerable<CultureInfo> cultureInfos)
{
// Note that the comparer will always be wrong, sadly. Each culture has its comparer
var dict = new Dictionary<string, int>(StringComparer.InvariantCultureIgnoreCase);
foreach (var culture in cultureInfos)
{
var monthNames = culture.DateTimeFormat.MonthNames;
for (int i = 0; i < monthNames.Length; i++)
{
string monthName = monthNames[i];
int other;
if (!dict.TryGetValue(monthName, out other))
{
dict[monthName] = i + 1;
}
else if (other != i + 1)
{
Debug.WriteLine($"Repeated month {monthName}: {i + 1} in {culture.Name} ({culture.DisplayName})");
}
}
}
return dict;
}
public int? GetMonthNumber(string monthName)
{
int monthNumber;
if (MonthToNumber.TryGetValue(monthName, out monthNumber))
{
return monthNumber;
}
return null;
}
}
像这样使用它:
var mnf = new MonthNameFinder();
int? n = mnf.GetMonthNumber("agosto");
if (n != null)
{
string name = new DateTime(1, n.Value, 1).ToString("MMMM", CultureInfo.GetCultureInfo("en-US"));
}
(请注意,您应该缓存 mnf
...构建起来可能相当昂贵)
嗯...我不喜欢...我有点 OC...我知道月份名称中存在一些冲突这一简单事实困扰着我。
这是第二个版本,使用 ILookup<>
甚至保存 CultureName
,这样就可以发现月份名称的语言。这
GetMonthNumbers(monthName)
现在 returns 一个 (int MonthNumber, string CultureName)[]
,一个匿名值类型的数组。可以明明拿第一个开心的过日子,也可以查一下有没有多个不同的MonthNumber
public class MonthNameFinder
{
private readonly ILookup<string, (int MonthNumber, string CultureName)> MonthToNumber;
public MonthNameFinder(params string[] cultures)
{
MonthToNumber = BuildLookup(cultures.Select(x => CultureInfo.GetCultureInfo(x)));
}
public MonthNameFinder(params CultureInfo[] cultureInfos)
{
MonthToNumber = BuildLookup(cultureInfos);
}
public MonthNameFinder(CultureTypes cultureTypes = CultureTypes.AllCultures)
{
MonthToNumber = BuildLookup(CultureInfo.GetCultures(cultureTypes));
}
private static ILookup<string, (int MonthNumber, string CultureName)> BuildLookup(IEnumerable<CultureInfo> cultureInfos)
{
// Note that the comparer will always be wrong, sadly. Each culture has its comparer
var lst = new List<(string Name, int MonthNumber, string CultureName)>();
foreach (var culture in cultureInfos)
{
var monthNames = culture.DateTimeFormat.MonthNames;
for (int i = 0; i < monthNames.Length; i++)
{
string monthName = monthNames[i];
lst.Add((monthName, i + 1, culture.Name));
}
}
return lst.OrderBy(x => x.Name)
.ThenBy(x => x.MonthNumber)
.ToLookup(x => x.Name, x => (x.MonthNumber, x.CultureName), StringComparer.InvariantCultureIgnoreCase);
}
public (int MonthNumber, string CultureName)[] GetMonthNumbers(string monthName)
{
return MonthToNumber[monthName].ToArray();
}
}
像这样使用它:
// This is an array of (MonthNumber, CultureName)
var mnf = new MonthNameFinder();
var numbers = mnf.GetMonthNumbers("agosto");
if (numbers.Length != 0)
{
string monthName = new DateTime(1, numbers[0].MonthNumber, 1).ToString("MMMM", CultureInfo.GetCultureInfo("en-US"));
}
(即使在这里你也应该缓存 mnf
...构建起来可能相当昂贵)
请注意,有许多相似的文化,因此 numbers
会很大(例如,仅意大利语就有 5 种文化,搜索 agosto 返回52 种不同的文化与月份 agosto.