Translated File Action
This type of extension is called whenever the Beebox creates a translated file in the "out" directory of a project. This can be triggered manually from the Beebox UI or by an automatic operation. Some use cases:
- Copy the translated file to another location
- Rename translated files, e.g. if you need to suffix or prefix file names.
- Store translated files to a content management system
- Track for logging purposes or triggering other actions
Adding the extension is done in a few steps:
- Add a class that extendst BeeboxTranslatedFileAction.
- Code the Process() method. It is called with full details per created translated file.
- Compile and install your dll.
The code below is a sample implementation. All interface methods are verbosely commented and should be self-explanatory.
Renaming files
If you plan to rename translated files, make sure to always leave the original translated file unchanged. Instead, create a copy of the file and save it under a different name (and ideally in a different location to avoid conflicts).
Configuration options
The sample implementation below copies and renames translated files according to a user configurable pattern: Each file is copied to out\_copy\... and the file name is prefixed with the target language code.
We added code to permit Beebox administrator to customize the target folder (_copy) and the file renaming individually per project.
Sample class
The Beebox extension below copies and renames translated files.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Wordbee.Beebox.Extensibility;
using System.IO;
namespace Acme.PseudoTranslationSample
{
public class SampleTranslatedFileAction : BeeboxTranslatedFileAction
{
/// <summary>
/// Gets the globally unique id of this extension.
/// </summary>
public override string ExtensionID { get { return "acme-tfa"; } }
/// <summary>
/// Gets if the extension is by default enabled. If false, then it must be enabled explicitly in each
/// Beebox project from the Beebox Admin UI.
/// </summary>
public override bool EnableByDefault { get { return false; } }
/// <summary>
/// Gets a name. Displayed in the Beebox extension manager page.
/// </summary>
public override string Name { get { return "Copy translated files"; } }
/// <summary>
/// Gets a description. Displayed in the Beebox extension manager page.
/// </summary>
public override string Description { get { return "Copies all translated files to another location."; } }
/// <summary>
/// Gets version number. Displayed in the Beebox extension manager page.
/// </summary>
public override string Version { get { return "1.0"; } }
/// <summary>
/// Gets the author. Displayed in the Beebox extension manager page.
/// </summary>
public override string Author { get { return "Acme Ltd"; } }
/// <summary>
/// Gets optional help description (not html!) of the configuration parameter.
/// By returning a non-null value, you explicitly tell the Beebox that this extension has a configurable parameter.
/// </summary>
public override string ParameterHelp
{
get
{
return
"Specify the sub directory inside out folder to which files will be copied." +
"Then the name transformation pattern. Separate with semi-colon.\n " +
"The name pattern may contain:\n " +
"{name} : The file name without extension.\n " +
"{extension} : The file extension.\n " +
"{tlocale} : The target language code.\n " +
"{slocale} : The source language code.\n ";
}
}
/// <summary>
/// Gets the default value of the parameter. Default can be changed by user.
/// </summary>
public override string ParameterDefault { get { return @"_copy; {tlocale}-{name}{extension}"; } }
/// <summary>
/// Validates the user parameters.
/// Return null if ok, otherwise return an error text.
/// </summary>
/// <param name="parameter">The parameter edited by a user.</param>
/// <returns>Null: parameter is ok. Otherwise return an error message.</returns>
public override string ValidateParameter(string parameter)
{
try
{
if (string.IsNullOrWhiteSpace(parameter)) return null;
var arr = parameter.Split(';');
if (arr.Length != 2) return "Specify a subdirectory followed by semi-colon followed by name pattern.";
// Here you need to check each array element in detail.
if (string.IsNullOrWhiteSpace(arr[0])) return "The subdirectory name is missing.";
if (string.IsNullOrWhiteSpace(arr[1])) return "The name transformation pattern is missing.";
return null;
}
catch (Exception e)
{
return "The parameter is not correct.";
}
}
/// <summary>
/// Called whenever a translated file was created in the OUT directory. Its location is:
/// {outdirectory}\{locale}\{relativepath}
/// When your code shall copy the file to another location, please keep in mind that the relativepath can include directories.
/// Example: "chapter\myfile1.doc", "data.xml", etc.
/// </summary>
/// <param name="projectkey">The project key</param>
/// <param name="path">The full path of the created translated file.</param>
/// <param name="outdirectory">The "OUT" directory path.</param>
/// <param name="targetlocale">The target language code</param>
/// <param name="filename">The relative path of the file with respect to {out directory}\{locale}(\){projectfolder}</param>
/// <param name="sourcelocale">The source language code</param>
/// <param name="configuration">The extension's parameters. You need to implement the respective virtual methods to permit configuring the parameter individually per project.</param>
public override void Process(
string projectkey,
string path,
string outdirectory,
string targetlocale,
string filename,
string sourcelocale,
IExtensionConfiguration configuration)
{
string subdirectory, namepattern;
// Get parameters
var parameter = configuration.Parameter ?? ParameterDefault;
var arr = parameter.Split(';');
subdirectory = arr[0].Trim();
namepattern = arr[1].Trim();
// Calculate target path
string name = Path.GetFileName(filename);
string newname = namepattern
.Replace("{name}", Path.GetFileNameWithoutExtension(name))
.Replace("{extension}", Path.GetExtension(name))
.Replace("{tlocale}", targetlocale)
.Replace("{slocale}", sourcelocale);
string targetPath = Path.Combine(outdirectory, subdirectory, targetlocale, Path.GetDirectoryName(filename), newname);
// Ensure that the file's directory exists. If not, create it now. Will raise exception if the target path is invalid.
EnsureDirectoryExists(targetPath);
// Copy file. May raise exception if the target file cannot be written.
File.Copy(path, targetPath, true);
}
/// <summary>
/// Creates all parent directories for the file path if these do not exist.
/// </summary>
/// <param name="filepath"></param>
private static void EnsureDirectoryExists(string filepath)
{
string d = Path.GetDirectoryName(filepath);
if (string.IsNullOrEmpty(d)) throw new Exception(string.Format("The file path '{0}' seems to be invalid. Failed to create all directories.", filepath));
if (!Directory.Exists(d))
{
EnsureDirectoryExists(d);
Directory.CreateDirectory(d);
}
}
}
}