When working with EPiServer sites, a not all that uncommon type of support case is the need to change text on a page which is not editable through the Edit mode. Quite often, this text is located in language files on the web server, and it may be rather tiresome for web editors having to send change requests to the support or development team just to change it. Perhaps, they even have to wait for the next planned release before they can get their update. I wrote a simple EPiServer Admin mode plugin which, added they get a little practice, will allow web administrators to make language file changes themselves; as well as creating new ones based on what they have already got. The source code is available at GitHub. Installation notes are included in the Readme.txt file.
This version makes use of the EPiServer Dynamic Data Store, and will only work with EPiServer CMS 6 R2.
IMPORTANT NOTE: You will want to make sure that you prevent any unauthorized access to your entire Plugins directory, or wherever you put this tool; for instance by using a location section in web.config only allowing access to WebAdmins. The way that file read and writes are currently managed in this tool makes room for quite a security issue. Read more here: Security fix for the Language File Editor tool in EPiServer CMS 6 R2
The Language File Editor
When opened, the plugin tool will display a long list of all XML files located in the EPiServer language folder. Each of these files may be edited, backed up, or removed. There is no automatic backup procedure present, so if changes are made to a file without a backup, the original information is lost.
If any of the language files have been backed up, an additional area will show above the file list. Here you will find a drop down list containing them all; along with a timestamp to help you find the right one. There is also a Restore button and a Delete all backups one. Restoring will, obviously, copy the backed up content into a file with the original name; creating a new one if it does no longer exist.
At the top of the language file editor you will find controls for creating new language files. Here it is possible to select a pattern file which will work as a template for the new one; all the content of this file is contained in the editor’s text boxes as an aid for the person translating. The drop down list holding the patterns is populated using the XML files in the language folder.
When creating a new file, or editing an old one, the web administrator will find themselves in a collapsable/expandable XML tree mirroring the content of the language file in question. If they are creating a new file they will be given the opportunity to give it a name in the top control box; this will be disabled when editing existing files.
As you can see the XML declaration is not editable. This is done by choise because it is highly unlikey that web administrators will ever need to change it. When altering attributes or content in the tree structure, the change is stored using JavaScript based functionality. Since it is not necessary to send information that has not been edited, this array is the only content that is sent back to the server on save; using JQuery AJAX and JSON. As a visual support for the translator, the text boxes will change color when they are updated.
Not losing changes on new release
So. Great. But what about deployment procedure? Will the changes made by web administrators be lost when there is a new release of the site? The short anwer is no. It won’t be. And it is not necessary to synchronize the files manually either. As soon as the web administrator hits the Save button on the editor page, all of the updated (and previously updated) fields are stored on the server, allowing the developers to reapply the changes by the click of a button. However, only the latest change made to a field is kept, so there is no history tracking involved.
Both the change tracking and the language file backups are stored in the EPiServer Dynamic Data Store, meaning that you will need to make changes if you are to run this in earlier versions than EPiServer CMS 6 R2. There is also a bit of audit logging going on, so if you use log4net you will see who is changing what and when.
I will be happy to accept bug reports, or feedback on this; so don’t be shy. And remember to always make backups as you are not blaming me if anything goes south; using this is all on you.
Super cool! I was just thinking about creating something like this today, and happen to see your post. Will try it out for sure.
Thanks Andreas, I hope that you will find it useful. Was thinking about a more EPi 5 friendly version as well, but have not gotten around to it yet.
Great post! How does this work in a load-balanced scenario? If the master files are still on disk, I guess it will be a problem. Is there anyway in EPiServer that we can switch to using DDS as master for language data?
Thank you Johan. It might be a good idea to add locking to certain parts; for instance while saving the file.
Yes, data being kept on disk could pose a problem, I believe setting up file replication between the load-balanced servers would help. Also keeping a dedicated editor server, disabling the edit and admin modes on the others, might make it easier.
I do not know of any simple way to use DDS instead of the language files, but I guess it could be possible to look at the EPiServer.Core.LanguageManager.Reload method making it set the LanguageDocument using the DDL instead of the private ReadLanguageFiles for some fake directory (as not to break the existing EPi language functionality).
Hi.
I’m using this module in a project and would like to put the source on http://www.coderesort.com/p/epicode together with other good EPiServer modules. Then every change / bug fix (?) and improvements of this project is available to everyone.
Is this ok by you ? I will add a readme.txt file in the project with a reference to your blog post.
/Øyvind
Hi Øyvind,
Yes, it is all good with me. I’m happy to hear that the code is getting used; what do you think of it so far? Please let me know when, and I’ll update the post to help people find it.
//Mathias
Hi Mathias – Have implemented this code on the latest project I am working on and just wanted to say thanks for this great plugin! Keep up the good work :)
Hi Adam!
Happy to hear that you like it. I am working on turning it into a NuGet package, while at the same time moving the code to a more test friendly Model-View-Presenter version. Code will be on GitHub when it’s done.
Cheers!
Mathias
We have a load balanced environment with two admin servers and six web servers. The language files are stored on disk of each individual servers. Quick questions
1. Is the plug-in able to modify files on the web servers as well, since it is installed on the admin servers I guess?
2. What is the alternate to having the xml files on disk? Can they be stored somewhere in EPiServer database so that there is only a single source?
3. Does the plug-in modify files on the disk?
Hello Sachin!
The plug-in will currently only modify the language files on the server that it is being used on. So if a web administrator is doing this on admin server A, the changes will not be written to the language directory of admin server B nor any of the web servers. You would need file replication between the servers for that.
In regards to your second question, have a look at Anders Hattestad‘s article LanguageManager using DynamicDataStore. I believe that you could probably use a variation of his code and modify the LanguageFileEditor so that they’ll work together. This is probably a better way to go rather than having some sort of file replication set up as you have multiple points from where the language files may be modified. I did a bit of research some half a year ago for Johan Book in a comment above regarding the DDS, might be worth having a peek at as well.
Yes, the physical files on disk are modified by the LanguageFileEditor. This is why I added the restore functionality to help prevent changes from being overwritten while for instance deploying new code.
I hope these answers help, let me know if I can be of any further assistance.
This seems very useful, but I’m slightly worried about its copyright. Do you grant a license (such as BSD, MIT, GPL, public domain or “yeah, use it as you wish”) to use this in real-world code?
Also, I might make some modifications for use with EPiServer 7. If I get anything useful done, I’d be happy to share it on github.
Hi Hannu,
Go ahead and use it / change it as you wish :) I realized now that I didn’t add the code to my repo for some reason, so it’s up there now.
Please do, would be interesting to see what changes need to be made getting it to work with EPi 7.
Cheers, Mathias
I finally took the time to really make this work and publish it on github. I initially settled for some hard-coded stuff and didn’t want to settle for that.
The code is available at https://github.com/dancek/EPiServer.Plugins.LanguageFileEditor . I’m sorry for not forking your blog repo, but I thought that this deserves to have its own repository.
You can see the changes for EPiServer 7 in this diff: https://github.com/dancek/EPiServer.Plugins.LanguageFileEditor/commit/4e9ab8d0d6ad28f249a9c5bb44bb9e0bc8d04f76
Cool, good job! I’ll have a look at it as soon as I get some time.
Cheers!
//Mathias
Looking good Hannu, great job!