diff --git a/src/Umbraco.Core/Services/ILocalizedTextService.cs b/src/Umbraco.Core/Services/ILocalizedTextService.cs
index dd6f9de883..097f1f689b 100644
--- a/src/Umbraco.Core/Services/ILocalizedTextService.cs
+++ b/src/Umbraco.Core/Services/ILocalizedTextService.cs
@@ -1,4 +1,6 @@
-using System.Globalization;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
namespace Umbraco.Core.Services
{
@@ -16,11 +18,14 @@ namespace Umbraco.Core.Services
///
///
///
- /// This can be null
+ /// This can be null
///
- string Localize(string key, CultureInfo culture,
-
- //TODO: Potentially this should be a dictionary to simplify things a little?
- object variables);
+ string Localize(string key, CultureInfo culture, IDictionary tokens);
+
+ ///
+ /// Returns all key/values in storage for the given culture
+ ///
+ ///
+ IDictionary GetAllStoredValues(CultureInfo culture);
}
}
diff --git a/src/Umbraco.Core/Services/LocalizedTextService.cs b/src/Umbraco.Core/Services/LocalizedTextService.cs
index d9a445b482..3610bee6cb 100644
--- a/src/Umbraco.Core/Services/LocalizedTextService.cs
+++ b/src/Umbraco.Core/Services/LocalizedTextService.cs
@@ -88,7 +88,7 @@ namespace Umbraco.Core.Services
_dictionarySource = source;
}
- public string Localize(string key, CultureInfo culture, object variables)
+ public string Localize(string key, CultureInfo culture, IDictionary tokens)
{
Mandate.ParameterNotNull(culture, "culture");
@@ -102,15 +102,63 @@ namespace Umbraco.Core.Services
if (_xmlSource != null)
{
- return GetFromXmlSource(culture, area, alias);
+ return GetFromXmlSource(culture, area, alias, tokens);
}
else
{
- return GetFromDictionarySource(culture, area, alias);
+ return GetFromDictionarySource(culture, area, alias, tokens);
}
}
- private string GetFromDictionarySource(CultureInfo culture, string area, string key)
+ ///
+ /// Returns all key/values in storage for the given culture
+ ///
+ ///
+ public IDictionary GetAllStoredValues(CultureInfo culture)
+ {
+ if (culture == null) throw new ArgumentNullException("culture");
+
+ var result = new Dictionary();
+
+ if (_xmlSource != null)
+ {
+ if (_xmlSource.ContainsKey(culture) == false)
+ {
+ throw new NullReferenceException("The culture specified " + culture + " was not found in any configured sources for this service");
+ }
+
+ //convert all areas + keys to a single key with a '/'
+ var areas = _xmlSource[culture].Value.XPathSelectElements("//area");
+ foreach (var area in areas)
+ {
+ var keys = area.XPathSelectElements("./key");
+ foreach (var key in keys)
+ {
+ result.Add(string.Format("{0}/{1}", (string) area.Attribute("alias"), (string) key.Attribute("alias")), key.Value);
+ }
+ }
+ }
+ else
+ {
+ if (_dictionarySource.ContainsKey(culture) == false)
+ {
+ throw new NullReferenceException("The culture specified " + culture + " was not found in any configured sources for this service");
+ }
+
+ //convert all areas + keys to a single key with a '/'
+ foreach (var area in _dictionarySource[culture])
+ {
+ foreach (var key in area.Value)
+ {
+ result.Add(string.Format("{0}/{1}", area.Key, key.Key), key.Value);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private string GetFromDictionarySource(CultureInfo culture, string area, string key, IDictionary tokens)
{
if (_dictionarySource.ContainsKey(culture) == false)
{
@@ -138,11 +186,16 @@ namespace Umbraco.Core.Services
.FirstOrDefault();
}
+ if (found != null)
+ {
+ return ParseTokens(found, tokens);
+ }
+
//NOTE: Based on how legacy works, the default text does not contain the area, just the key
- return found ?? "[" + key + "]";
+ return "[" + key + "]";
}
- private string GetFromXmlSource(CultureInfo culture, string area, string key)
+ private string GetFromXmlSource(CultureInfo culture, string area, string key, IDictionary tokens)
{
if (_xmlSource.ContainsKey(culture) == false)
{
@@ -157,13 +210,43 @@ namespace Umbraco.Core.Services
var found = cultureSource.XPathSelectElement(xpath);
- return found == null
- //NOTE: Based on how legacy works, the default text does not contain the area, just the key
- ? "[" + key + "]"
- : found.Value;
+ if (found != null)
+ {
+ return ParseTokens(found.Value, tokens);
+ }
+
+ //NOTE: Based on how legacy works, the default text does not contain the area, just the key
+ return "[" + key + "]";
+ }
+
+ ///
+ /// Parses the tokens in the value
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// This is based on how the legacy ui localized text worked, each token was just a sequential value delimited with a % symbol.
+ /// For example: hello %0%, you are %1% !
+ ///
+ /// Since we're going to continue using the same language files for now, the token system needs to remain the same. With our new service
+ /// we support a dictionary which means in the future we can really have any sort of token system.
+ /// Currently though, the token key's will need to be an integer and sequential - though we aren't going to throw exceptions if that is not the case.
+ ///
+ internal string ParseTokens(string value, IDictionary tokens)
+ {
+ if (tokens == null || tokens.Any() == false)
+ {
+ return value;
+ }
+
+ foreach (var token in tokens)
+ {
+ value = value.Replace(string.Format("{0}{1}{0}", "%", token.Key), token.Value);
+ }
+
+ return value;
}
-
-
}
}
diff --git a/src/Umbraco.Tests/Services/LocalizedTextServiceTests.cs b/src/Umbraco.Tests/Services/LocalizedTextServiceTests.cs
index 38f0f1a1ce..ba1ad70b8c 100644
--- a/src/Umbraco.Tests/Services/LocalizedTextServiceTests.cs
+++ b/src/Umbraco.Tests/Services/LocalizedTextServiceTests.cs
@@ -13,6 +13,81 @@ namespace Umbraco.Tests.Services
[TestFixture]
public class LocalizedTextServiceTests
{
+ [Test]
+ public void Using_Dictionary_Gets_All_Stored_Values()
+ {
+ var culture = CultureInfo.GetCultureInfo("en-US");
+ var txtService = new LocalizedTextService(
+ new Dictionary>>
+ {
+ {
+ culture, new Dictionary>
+ {
+ {
+ "testArea1", new Dictionary
+ {
+ {"testKey1", "testValue1"},
+ {"testKey2", "testValue2"}
+ }
+ },
+ {
+ "testArea2", new Dictionary
+ {
+ {"blah1", "blahValue1"},
+ {"blah2", "blahValue2"}
+ }
+ },
+ }
+ }
+ });
+
+ var result = txtService.GetAllStoredValues(culture);
+
+ Assert.AreEqual(4, result.Count());
+ Assert.AreEqual("testArea1/testKey1", result.ElementAt(0).Key);
+ Assert.AreEqual("testArea1/testKey2", result.ElementAt(1).Key);
+ Assert.AreEqual("testArea2/blah1", result.ElementAt(2).Key);
+ Assert.AreEqual("testArea2/blah2", result.ElementAt(3).Key);
+ Assert.AreEqual("testValue1", result["testArea1/testKey1"]);
+ Assert.AreEqual("testValue2", result["testArea1/testKey2"]);
+ Assert.AreEqual("blahValue1", result["testArea2/blah1"]);
+ Assert.AreEqual("blahValue2", result["testArea2/blah2"]);
+
+ }
+
+ [Test]
+ public void Using_XDocument_Gets_All_Stored_Values()
+ {
+ var culture = CultureInfo.GetCultureInfo("en-US");
+ var txtService = new LocalizedTextService(
+ new Dictionary>
+ {
+ {
+ culture, new Lazy(() => new XDocument(
+ new XElement("language",
+ new XElement("area", new XAttribute("alias", "testArea1"),
+ new XElement("key", new XAttribute("alias", "testKey1"), "testValue1"),
+ new XElement("key", new XAttribute("alias", "testKey2"), "testValue2")),
+ new XElement("area", new XAttribute("alias", "testArea2"),
+ new XElement("key", new XAttribute("alias", "blah1"), "blahValue1"),
+ new XElement("key", new XAttribute("alias", "blah2"), "blahValue2")))))
+ }
+ });
+
+ var result = txtService.GetAllStoredValues(culture);
+
+ Assert.AreEqual(4, result.Count());
+ Assert.AreEqual("testArea1/testKey1", result.ElementAt(0).Key);
+ Assert.AreEqual("testArea1/testKey2", result.ElementAt(1).Key);
+ Assert.AreEqual("testArea2/blah1", result.ElementAt(2).Key);
+ Assert.AreEqual("testArea2/blah2", result.ElementAt(3).Key);
+ Assert.AreEqual("testValue1", result["testArea1/testKey1"]);
+ Assert.AreEqual("testValue2", result["testArea1/testKey2"]);
+ Assert.AreEqual("blahValue1", result["testArea2/blah1"]);
+ Assert.AreEqual("blahValue2", result["testArea2/blah2"]);
+
+ }
+
[Test]
public void Using_Dictionary_Returns_Text_With_Area()
@@ -115,6 +190,32 @@ namespace Umbraco.Tests.Services
Assert.AreEqual("[doNotFind]", result);
}
+ [Test]
+ public void Using_Dictionary_Returns_Tokenized_Text()
+ {
+ var culture = CultureInfo.GetCultureInfo("en-US");
+ var txtService = new LocalizedTextService(
+ new Dictionary>>
+ {
+ {
+ culture, new Dictionary>
+ {
+ {
+ "testArea", new Dictionary
+ {
+ {"testKey", "Hello %0%, you are such a %1% %2%"}
+ }
+ }
+ }
+ }
+ });
+
+ var result = txtService.Localize("testKey", culture,
+ new Dictionary { { "0", "world" }, { "1", "great" }, { "2", "planet" } });
+
+ Assert.AreEqual("Hello world, you are such a great planet", result);
+ }
+
[Test]
public void Using_XDocument_Returns_Text_With_Area()
{
@@ -196,6 +297,27 @@ namespace Umbraco.Tests.Services
Assert.AreEqual("[doNotFind]", result);
}
+ [Test]
+ public void Using_XDocument_Returns_Tokenized_Text()
+ {
+ var culture = CultureInfo.GetCultureInfo("en-US");
+ var txtService = new LocalizedTextService(
+ new Dictionary>
+ {
+ {
+ culture, new Lazy(() => new XDocument(
+ new XElement("area", new XAttribute("alias", "testArea"),
+ new XElement("key", new XAttribute("alias", "testKey"),
+ "Hello %0%, you are such a %1% %2%"))))
+ }
+ });
+
+ var result = txtService.Localize("testKey", culture,
+ new Dictionary { { "0", "world" }, { "1", "great" }, { "2", "planet" } });
+
+ Assert.AreEqual("Hello world, you are such a great planet", result);
+ }
+
[Test]
public void Using_Dictionary_Throws_When_No_Culture_Found()
{
@@ -216,7 +338,7 @@ namespace Umbraco.Tests.Services
}
});
- Assert.Throws(() => txtService.Localize("testArea/testKey", CultureInfo.GetCultureInfo("en-AU")));
+ Assert.Throws(() => txtService.Localize("testArea/testKey", CultureInfo.GetCultureInfo("en-AU")));
}
[Test]
diff --git a/src/umbraco.businesslogic/ui.cs b/src/umbraco.businesslogic/ui.cs
index 509df667aa..2ab3528ac3 100644
--- a/src/umbraco.businesslogic/ui.cs
+++ b/src/umbraco.businesslogic/ui.cs
@@ -1,7 +1,10 @@
using System;
+using System.Collections;
+using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
+using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Web;
@@ -360,24 +363,25 @@ namespace umbraco
//return "[" + key + "]";
}
- private static string GetStringWithVars(string stringWithVars, string[] variables)
- {
- var vars = Regex.Matches(stringWithVars, @"\%(\d)\%",
- RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
- foreach (Match var in vars)
- {
- stringWithVars = stringWithVars.Replace(
- var.Value,
- variables[Convert.ToInt32(var.Groups[0].Value.Replace("%", ""))]);
- }
- return stringWithVars;
- }
+ //private static string GetStringWithVars(string stringWithVars, string[] variables)
+ //{
+ // var vars = Regex.Matches(stringWithVars, @"\%(\d)\%",
+ // RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
+ // foreach (Match var in vars)
+ // {
+ // stringWithVars = stringWithVars.Replace(
+ // var.Value,
+ // variables[Convert.ToInt32(var.Groups[0].Value.Replace("%", ""))]);
+ // }
+ // return stringWithVars;
+ //}
///
/// Gets the language file as a xml document.
///
/// The language.
///
+ [Obsolete("This is no longer used and will be removed from the codebase in future versions")]
public static XmlDocument getLanguageFile(string language)
{
var cacheKey = "uitext_" + language;
@@ -414,10 +418,15 @@ namespace umbraco
}
-
- internal static object ConvertToObjectVars(string[] variables)
+ ///
+ /// Convert an array of strings to a dictionary of indicies -> values
+ ///
+ ///
+ ///
+ internal static IDictionary ConvertToObjectVars(string[] variables)
{
- throw new NotImplementedException();
+ return variables.Select((s, i) => new {index = i.ToString(CultureInfo.InvariantCulture), value = s})
+ .ToDictionary(keyvals => keyvals.index, keyvals => keyvals.value);
}
}