| 

.NET C# Java Javascript Exception

2
Hallo,
ich wollte mich mal erkundigen, wie Ihr eure Asp.Net MVC 3 Projekte lokalisiert. Macht Ihr das wie in "normalen" ASP.Net oder verwendet ihr andere Möglichkeiten?
15.02.2011
phlow666 922 1 9
5 Antworten
2
Schau dir mal folgenden Blog-Eintrag an.
15.02.2011
Konstantin 3,7k 1 8
3
Das "Translate" ist von dir, oder? Wie sieht das ganze dann als intern aus?


Ja. Im Folgenden eine gekürzte Version, die sich auf sprachabhängige Übersetzungen beschränkt (im Projekt haben wir mehr Abhängigkeiten):

HtmlHelperExtensions.cs

namespace System.Web.Mvc.Html
{
public static class HtmlHelperExtensions
{
public static MvcHtmlString Translate(this HtmlHelper helper, string resourceKey)
{
return MvcHtmlString.Create(Project.Resources.Translate(resourceKey));
}
}
}


Resources.cs

namespace Project
{
using Project.Models;

public static class Resources
{
public static readonly CultureInfo DefaultCulture = new CultureInfo("de-de");
public static readonly TimeSpan ResourceCacheExpiration = TimeSpan.FromSeconds(30);

static readonly object s_lock = new object();
static bool s_initialized;
static DateTime s_expiration;

static IDictionary<string, IDictionary<string, string>> s_resources;

static internal void InitializeOnce(HttpApplicationState application)
{
if (!s_initialized || DateTime.UtcNow > s_expiration)
{
lock (s_lock)
{
if (!s_initialized || DateTime.UtcNow > s_expiration)
{
var storageAccount = application["CloudStorageAccount"] as Microsoft.WindowsAzure.CloudStorageAccount;
var context = new Project.Models.ProjectDataServiceContext(
storageAccount.TableEndpoint.ToString(),
storageAccount.Credentials);

s_resources = new SortedDictionary<string, IDictionary<string, string>>();

var resources = from r in context.ResourceTable
select r;

var query = resources.AsTableServiceQuery<Resource>();

foreach (var resource in query.Execute())
{
var culture = string.IsNullOrEmpty(resource.PartitionKey) ? DefaultCulture.Name.ToLowerInvariant() : resource.PartitionKey;
var key = resource.RowKey;
var value = resource.Value;

if (!s_resources.ContainsKey(culture))
s_resources.Add(culture, new SortedDictionary<string, string>());

s_resources[culture][key] = value;
}

s_expiration = DateTime.UtcNow.Add(ResourceCacheExpiration);
s_initialized = true;
}
}
}
}

public static string Translate(string resourceKey)
{
if (!s_initialized)
throw new Exception("Dictionary is not initialized.");

var context = (ProjectContext)HttpContext.Current.Items["ProjectContext"];
var currentCulture = context.Culture;

var cultures = new[] {
currentCulture.Name.ToLowerInvariant(),
currentCulture.TwoLetterISOLanguageName,
string.Empty // fallback values
}.Distinct();

var resourceDictionaries =
from culture in cultures
where s_resources.ContainsKey(culture)
select s_resources[culture];

var resourceQuery = (from resources in resourceDictionaries
where resources.ContainsKey(resourceKey)
select resources[resourceKey]).Concat(new string[] { resourceKey });

string result;

lock (s_lock)
{
result = resourceQuery.First();
}

if (DateTime.UtcNow > s_expiration)
{
System.Threading.Tasks.Task.Factory.StartNew((application) =>
{
InitializeOnce((HttpApplicationState)application);
}, HttpContext.Current.Application);
}

return result;
}
}
}


Die Initialisierung wird in der Global.asax in Application_Start aufgerufen. Der Cache ist nur während der Entwicklung auf 30 Sekunden beschränkt. Auch wenn das Neuladen des Caches selbst beim 30 Sekunden Rythmus nicht auffällt, werden wir später in der Produktivumgebung auf eine oder mehrere Stunden hoch gehen.
15.02.2011
Daniel Kuppitz 596 1 7
Sieht gut aus. Werde ich mal testen. Danke auf jeden Fall.
phlow666 16.02.2011
2
Microsofts Resourcenmodell hat sich für mich eher als untauglich erwiesen. In kleinen Projekten ist meist gar keine Lokalisierung notwendig und in größeren Projekte wollte der Kunde bei Übersetzungen immer gern selbst Hand anlegen.

Anfangs habe ich die Übersetzungen dann noch von Übersetzern entgegen genommen und in die Resourcendateien übernommen. Als mir das irgendwann zu viel Zeitverschwendung war, bin ich auf die Suche nach Alternativen gegangen, habe aber nicht wirklich etwas brauchbares gefunden. In einem aktuellen Projekt kommt nun eine Lokalisierung der Marke Eigenbau zum Einsatz. Der Aufruf relativ simpel; z.B.:

<!-- snip -->
<h1>@Html.Translate("Title_CustomerRegistration")</h1>
<p>
@Html.TranslatedLabelFor(model => model.Customer.Email, "Label_Email")<br/>
@Html.TextBoxFor(model => model.Customer.Email)
</p>
<!-- snip -->

Mein Kunde hat nun die Möglichkeit, diese Platzhalter über eine Admin-Oberfläche in jeder x-beliebigen Sprache zu pflegen. Gespeichert werden die Übersetzungen in der Azure Table Storage.

Fazit:
Kunde ist begeistert von der Marke Eigenbau und ich habe wieder mehr Zeit, mich auf's Wesentliche zu konzentrieren.
15.02.2011
Daniel Kuppitz 596 1 7
1
Das "Translate" ist von dir, oder? Wie sieht das ganze dann als intern aus?
phlow666 15.02.2011
2
Ich mache das komplett auf der Client Seite (also Browser).

Grobes Vorgehen:
- Die ASP.Net Anwendung liefert statische Texte komplett nur mit Platzhaltern aus. In Elementen und in Attributen.
- Also statt <p>Hello Welt</p> liefere ich <p>%hello.world%</p>
- Der Browser übersetzt dann nachdem Laden des DOM Models per JavaScript alle Platzhalter gegen den übersetzten Text.
- Auf dem Server habe ich dann statische JSON Dateien liegen. Pro Sprache eine
- z.B. "strings\de.js" für die Deutschen Texte. Dort ist steht dann als Map "hello.world" : "Hallo Welt", ....

Das hat zum einen den Vorteil das der Browser die Übersetzung vornimmt. Das ist heutzutage ein leichtes für den. Die lokalisierten Dateien sind statisch und können sehr gut gecachet werden. Der Server selbst wird geschont. Und vor allem muss ich auf dem Server mich nicht mit Resource-Dateien herumschlagen. Die Lokalisierten Dateien kann ich auch verändern ohne das neu compiliert werden muss. Bei eingebundenen Resourcedateien muss ich das Programm immer neu bilden und wenn die Lokalisierung ausser Haus gemacht wird ist es auch problematischer.

Hier eine kleine Javascrip Lib die das dynamische Ersetzen übernimmt:

/*
General Javascript library
2010 Stefc
*/
String.prototype.trim = function(){
return (this.replace(/^[\s\xA0]+/, "").replace(/[\s\xA0]+$/,""))};

String.prototype.startsWith = function(str) {
return (this.match("^"+str)==str)};

String.prototype.endsWith = function(str) {
return (this.match(str+"$")==str)};

String.prototype.transform = function() {
if(this.check())
{
var key =this.slice(1,this.length-1).toLowerCase();
if(strings.hasOwnProperty(key))
return strings[key];
}
return this;
};

String.prototype.check = function() {
return this.match("%.+%")!=null;}

function traverseDOMTree(node) {
if (node)
{
if(node.nodeValue && (node.nodeType == 3))
{
if(node.nodeValue.check())
node.nodeValue = node.nodeValue.transform();
}

var attrs = node.attributes;
if(attrs && attrs.length)
{
for (var length=attrs.length, j = 0; j < length;j++)
{
if(attrs[j].nodeValue.check())
{
node.setAttribute(attrs[j].name,attrs[j].nodeValue.transform());
}
}
}

var i=0;
var child=node.childNodes;
while (child)
{
traverseDOMTree(child);
child=node.childNodes[++i];
}
}
};

Im HTML mache ich dann folgendes:
<script type="text/javascript" src="/strings/de.js"></script>
<body onload="javascript:traverseDOMTree(document.documentElement);">
</body>

welche /strings/de.js ich dannn lade wird dynamisch von der asp App entschieden.

hier ein Auszug aus der de.js
/* German resource strings */
var strings = {

// Anwendung
"app.title":"test",

// Kommandos
"cmd.login":"Anmelden",
"cmd.logout":"Abmelden",
"cmd.registration":"Registrierung",
"cmd.register":"Registrieren",
"cmd.lostpassword":"Passwort vergessen",
}
[/code]
Achso in den Attriobuten und Elementen steht dann immer %app.title% bzw. %cmd.login%
15.02.2011
stefc 268 1 6
stefc 268 1 6
1
Das hört sich auch sehr cool an. Wäre super wenn Du das posten könntest. Danke.
phlow666 15.02.2011
0
Ich empfehle dieses Lokalisierungstool für die Übersetzung von .NET Projekte: https://poeditor.com/
05.05.2015

Stelle deine .net-Frage jetzt!
TOP TECHNOLOGIES CONSULTING GmbH