Post

Localization Provider - Import and Export (Merge)

It’s been awhile since last update for DbLocalizationProvider for EPiServer. Anyway things been in my backlog. Period around New Year is not the most productive for me :) This blog post will describe some of the interesting stuff I’ve been lately busy with.

Export & Import - View Diff

Once upon a time I got sick of merging and importing new resources from staging environment (with adjusted translations by editors) into production database where on the other hand editors already made changes to existing resources. Up till now import process only supported partial import or full import. Partial import was dealing with only new resources (those ones that were not in target database), however full import - on the other hand - was used to flush everything and import stuff from exported file. Kinda worked, but it was v0.1 of this export/import component. Pretty green.

Updates to this story was one of the main focus for this upcoming version. Eventually if you are importing resources from other environment, now your import experience might look like this:

To share the code would be overkill here in this post. Better sit back and relax watching import in action. Enjoy!

DbLocalizationProvider - Export_Import from Valdis Iljuconoks on Vimeo.

Resource Keys for Enum

Sometimes (usage for me was EPiServer visitor groups) you just need to control naming for each individual Enum item. Now you can do that with [ResourceKey] attribute. Hope code explains how it might look:

1
2
3
4
5
6
7
8
9
10
11
12
[LocalizedResource(KeyPrefix = "/this/is/prefix/")]
public enum ThisIsMyStatus
{
    [ResourceKey("nothing")]
    None,

    [ResourceKey("something")]
    Some,

    [ResourceKey("anything")]
    Any
}

For instance you have following visitor group criteria:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
namespace My.Project.Namespace
{

[VisitorGroupCriterion(..,
    LanguagePath = "/visitorgroupscriterias/usernamecriterion")]
public class UsernameCriterion : CriterionBase<UsernameCriterionModel>
{
    ...
}

public class UsernameCriterionModel : CriteriaPackModelBase
{
    [Required]
    [DojoWidget(SelectionFactoryType = typeof(EnumSelectionFactory))]
    public UsernameValueCondition Condition { get; set; }

    public string Value { get; set; }
}

public enum UsernameValueCondition
{
    Matches,
    StartsWith,
    EndsWith,
    Contains
}

So EPiServer will look after resources with following key:

1
/enums/my/project/namespace/usernamecriterion/usernamevaluecondition

and then name of the Enum. So you can control this and decorate each enum member with ResourceKey attribute to generate specific keys if needed.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
namespace My.Project.Namespace
{
    [LocalizedResource(KeyPrefix = "/enums/my/project/namespace/usernamecriterion/usernamevaluecondition")]
    public enum UsernameValueCondition
    {
        [ResourceKey("matches")]
        Matches,
        [ResourceKey("startswith")]
        StartsWith,
        [ResourceKey("endswith")]
        EndsWith,
        [ResourceKey("contains")]
        Contains
    }
}

Maybe it’s worth just to create new attribute - like [EPiServerEnumResource] or something - namespace and member resource key calculations would be done for me?! I know - I’m lazy.. Sorry..

Class Fields

This is smaller update, but still important. Developer writing code below would expect at least one resource to be generated. But it would not happen (with older library versions).

1
2
3
4
5
6
7
8
namespace My.Project.Namespace
{
    [LocalizedResource]
    public class MyResources
    {
        public static PageHeader = "This is page header";
    }
}

Seems legit, but issue here is that PageHeader is class field and not property. Thanks to my colleague who discovered this. He just forgot to add “>” symbol at the end of the assignment to convert from field to property:

1
2
3
4
5
6
7
8
namespace My.Project.Namespace
{
    [LocalizedResource]
    public class MyResources
    {
        public static PageHeader => "This is page header";
    }
}

Now this has been fixed and class fields are also supported. Static and instance ones.

Distributed Concurrency Issue

Everything went great and localization provider proved to be solid and developer friendly approach to localize EPiServer (and not only EPiServer - provider runs outside of it just fine) applications. Until we deployed application with new pending resources to Azure deployment slot with more than 1 instance.. At the end duplicate resource keys were registered. Thanks to another colleague for giving some hints. So over the weekend while testing 10 concurrent instances with 10,000 resources - I came also to some performance issues. However, not sure if this might ever be actual real life case tho… At least stress testing gave some ideas how to improve performance in “normal” cases with just a few hundred resources. Startup performance boost average is about 30%.

I’m still struggling a bit with the best approach for distributed concurrency and how to properly address it, but at least - duplicate resource keys (which would be disaster) should not be registered.

More info

Happy localizing!

[eof]

This post is licensed under CC BY 4.0 by the author.

Comments powered by Disqus.