|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Dear Alchemy Technology User, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
In this edition of Techbytes, I concentrate on .NET projects, from preparing project files for Localization to Localizing them in Catalyst. With some really handy tips on best practices in developing localizable .NET projects to maximize Catalyst's Visual translation environment. Remember all the previous released articles are available on our website, in the Support section. Use your Support Centre login to access all the past articles along with other resources available to our premium support members. As always, don't hesitate to let me know if there is any topic you would like covered in this TechBytes newsletter. Cyril Vallin |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Catalyst 11 SP2 released
Review the notification Email directly at this page: Catalyst 11 SP2 release
Where to put source language resources The source language is the language in which a piece of software has been developed. Resources in this language can be placed in a main assembly, which will then contain code and resources, or in a satellite, the satellite will then contain just resources and the main assembly will contain just code. Our recommendation is that the source language resources be stored in the main assembly. This is the default setting in the development environment. However, as well as ensuring that there is no <UICulture> entry in the csproj file, the following should be added in AssemblyInfo.cs, it explicitly states the location of the source language resources:
String tables If you are writing a purely XAML GUI application, we recommend you don't use a ResX string table to store UI strings. Leave them all in XAML declaration or alternatively use a resource dictionary. A resource dictionary is a XAML construct; however it does not typically store any UI, just a list of strings with IDs, wrapped in some XAML mark-up. Resource dictionaries can also store style information, themes and binary resources among other things. For simplicity, each type of resource can be factored into a different resource dictionary and these can be merged later if required. The resource dictionary can be stored at application level and referenced throughout the WPF application. There is a lot of built-in support for this mechanism and it's very flexible when setup correctly, more so than ResX files. Resource dictionaries should not be used to store visual templates as the contents of resource dictionaries cannot be visualized. File Preparation
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Localizing .NET framework applications
Localizing .resx resource files or compiled .NET assemblies Catalyst supports both .resx and compiled binaries (.exe & .dll), and in both cases no configuration of parsing rules is necessary. As we advise with Win32 files, localizing compiled binaries in Catalyst is a better option considering the following benefits:
Referenced assemblies In order to generate a visual display of the Forms and BAML dialogs Catalyst uses the .NET Framework to emulate the UI. Consequently all referenced assemblies need to be available to successfully display dialogs in their intended layout. Catalyst gives invaluable feedback when inserting assemblies into a project. This feedback is listed in the Results window. For example, here is a standalone WPF application inserted successfully. The Results window reports no missing referenced assembly: If the assemblies inserted in a Catalyst project depend on referenced assemblies to render dialogs and forms, the later need to be present in the same directory. Catalyst loads all referenced assemblies along with the main assemblies. Although referenced assemblies are not visible in Catalyst's Navigator Window, they are loaded and available for the .NET Framework while emulating the assemblies' code. Example, if you are inserting MyApp.dll which has 2 referenced assemblies (filea.dll and fileb.dll), those 2 referenced assembly files need to be in the same folder as MyApp.dll. With the files present, the Results window will not report errors. If missing, the Results window will warn on each missing referenced assembly. Although it is possible to insert and translate assemblies in Catalyst without the referenced assemblies available, it is not recommended as important information is missing.
Example of missing referenced assembly on inserting a main assembly in Catalyst. The Form displayed in Visual View is missing resources: The same form in visual view with the Referenced assembly present on insertion:
Signed or Strong-named assemblies Assembly signing (also called strong-name signing) gives an application or component a unique identity that other software can use to identify and refer explicitly to it. A strong name consists of its simple text name, version number, culture information (if provided), plus a public/private key pair. This information is stored in a key file. Localizing a signed main assembly requires the localized assemblies signed also. The key file (.snk) can be configured in Catalyst's options under FILE > Options > .NET Framework. Often the private key file is not available to the localization team, or even development team until the product release. The public key however is often available. In this case, you may opt to delay sign the satellite assemblies. Select "Auto detect public keys and delay sign satellites on creation" option as seen in screenshot above. Microsoft reference on delay signing: http://msdn.microsoft.com/en-us/library/t07a3dye.aspx
Delayed signed assemblies
Obfuscated assemblies In .NET, the inner workings of assemblies can be examined using tools such as .NET Reflector or ILSpy. This can reveal a lot about what a DLL does and how it works. This is useful from an openness and transparency point of view, but less so from the point of view of protecting intellectual property. To hide code and algorithms and to protect their intellectual property, assemblies can be obfuscated. Obfuscation is a process that encrypts class and function names so they are no longer readable. The downside is that this process also encrypts the information Catalyst uses to load these assemblies either as referenced assemblies or for localization. If you are localizing assemblies which are obfuscated, you will need to require unobfuscated copies of the assemblies. The localized satellite assemblies can then be obfuscated along with the main assemblies.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Best practices for developing localizable .NET applications Catalyst’s Visual View calls on the Microsoft .NET Framework to create instances of complex .NET windows for display. The .NET Framework is sometimes unable to create these objects. After a failure Catalyst attempts to generate an alternative fall-back Visual View. This fall-back view can result in windows that don’t appear exactly as they would at runtime in the parent application. While all content is made available for localization, missing user interface components can sometimes lead to loss of context during the translation process. One of the most common causes of a window not displaying is unhandled exceptions in client code. The .NET Framework is unable to create a window because its constructor throws an exception and this exception remains unhandled. There are a number of suggestions for avoiding this situation. These are outlined below. Try-Catch Blocks Avoid unhandled exceptions: Use a ‘try-catch’ statement around code in the constructor that may throw an exception.
Check if Catalyst is calling a constructor Another option for avoiding unhandled exceptions is to check if Catalyst is calling your constructor, you can then follow an appropriate code path: class MyClass
Attach Event Handlers Where appropriate, attach event handlers to these events: Application.ThreadException AppDomain.CurrentDomain.UnhandledException This will deal with these exceptions. These event handlers would not generally terminate the thread but would allow components of the user interface to continue functioning. These user interface components may be required by Catalyst. Call InitializeComponents() Early Wait until after the call to InitializeComponent () before adding more logic to the constructor. The InitializeComponent () method should be complete before any code that is liable to throw an exception is added.
Avoid resources that may not be present If possible, try to avoid connecting to data sources or resources that may not exist in certain environments. When an application is installed on a client’s machine, it may be that a certain file or a database is always present (the installer may look after this). However, this may not be the case during localisation. Try to avoid dependencies such as this in the constructor or InitializeComponent () calls. This is not always possible and if not, that resource will need to be present during localization.
Public Constructors with no Arguments For a given window’s class, implement a public constructor, which takes no arguments, if one does not already exist. Such a constructor is easier for Catalyst to call.
Handle Null Parameters In certain circumstances Catalyst can ask the .NET Framework to create objects using a constructor which takes parameters; however, when the constructor is called by Catalyst the parameters passed can be null. Ideally, code should check for the possibility of null parameters and handle any resulting exceptions gracefully.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Mapping of XLIFF state to Catalyst status This article references the correspondence (mapping) between the State attribute found in XLIFF for individual string and the Status in Alchemy Catalyst. Inserting an XLIFF file in a Catalyst project, a mapping of the state and state-qualifier values to Catalyst states is applied as follows:
STATE (independent values) State = The status of a particular translation in a <target> or <bin-target> element in XLIFF format
This Source != Target takes precedence when dealing with the Untranslated states.
STATE-QUALIFIER (independent values) State-qualifier = Describes the state of a particular translation in a <target> or <bin-target> element in XLIFF format.
STATE and STATE-QUALIFIER (combined values) When both state and state-qualifier exists in the same <trans-unit>, this is the combined status that should be adopted when parsing the file into Catalyst:
When neither state nor state-qualifier is found in the <trans-unit> and Source does not equal Target, the Target must contain a translation; therefore Catalyst parses the segments with For Review status. Source != Target takes precedence when dealing with the Untranslated state.
Extracting out of Catalyst to XLIFF When writing out to XLIFF format through Extract Files... the Catalyst status is mapped to the XLIFF state values as follows: Writing out Edited segments
Maintaining XLIFF state and state-qualifier attribute that have not been edited Maintain state attributes If we are not editing segments, we should maintain the state value that was there e.g.
Maintain state-qualifier attributes If we are not editing segments, we should maintain the state-qualifier value that was there e.g.
Reverted XLIFF written out of Catalyst When a file already containing existing states in the XLIFF file has been reverted within Catalyst and then extracted without any translation, this is the status on those target nodes when extracted.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Conclusion
Thanks for taking the time to read this instalment of TechBytes. It has been fun to write and I hope you found some if not all of it beneficial. We always welcome new article ideas, so if there is a feature you feel works really well and is worth mentioning, or indeed if clarification on a particular topic would help you, please let me know so together we can make TechBytes as useful as possible for everyone. My best wishes |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||