I'm having a dialog based app written in VC++ using Visual Studio 6. It's a simple app with very few texts, but now those needs to support multiple languages. As it's not many texts, the plan is to add all the different languages into just one string table with a unique identifier. So now a sample string table looks like this,
STRINGTABLE
BEGIN
IDS_STRING_OK_BUTTON_ENG "OK" //English text
IDS_STRING_EXIT_BUTTON_ENG "Exit" //English text
IDS_STRING_OK_BUTTON_FRA "D'accord" //French text
IDS_STRING_EXIT_BUTTON_FRA "Sortie" //French text
END
Now i have a function that will return a string based on the OS language setting.
CString strLang = "";
//Retrieves the system default locale identifier
LCID lcid = GetSystemDefaultLCID();
//Determine the language identifier from the locale identifier
LANGID langid = LANGIDFROMLCID(lcid);
//Does many processing here........
//.................................
//.................................
// So if English is the OS language then this function will return "_ENG".
Now in another part of the code, this unique language ID is concatenated with another string to find the language specific text.
CString okButton = "IDS_STRING_OK_BUTTON" + m_strLanguageIndex; //Here m_strLanguageIndex for example will be "_ENG"
So this way, i can have just one string table with all different languages and then use the above method to create a unique resource ID.
But now the challenge is, the resource IDs in resource.h file are integers. So the above CString is of no use to find the corresponding the text.
So am not sure whether this is going to work. Am just throwing it out to see whether anyone has better ideas or have any suggestion to make the above method work.
I don't want to create multiple DLLs for every language as this is a simple dialog based app.
Win32 resources are stored in a hierarchy; type\name\language and the resource functions will look for a resource matching the threads language if it exists. This will allow you to use an id like IDS_STRING_OK_BUTTON in your code and your resources will contain two different string tables, one for each language.
In a .RC file you can use the LANGUAGE statement to create translated copies of different resources:
Defines the language for all resources up to the next LANGUAGE statement or to the end of the file.
When the LANGUAGE statement appears before the beginning of the body of an ACCELERATORS, DIALOGEX, MENU, RCDATA, or STRINGTABLE resource definition, the specified language applies only to that resource.
Another common way to provide translation support is to create a resource .DLL for each language and just load the desired .DLL and use its HMODULE handle when loading resources. Windows can do the work for you if you create MUI resources.
Related
We already have a vast group of .rpx files that contain report definitions in german. We have used scripting to translate some of the text to romansh (official swiss language used by <1% of population), yet it has been requested.
The vision now is to create reports in french and maybe italian as well. Yet we are well aware that the current scripting approach like:
if (txtSprache.Text == "RM")
{
lblAbonnentenNr.Text = "Abo-nr.:";
lblAbrechnungVon.Text = "Quen dils:";
lblBis.Text = " -";
lblZahlbarBis.Text = "Pagabel tochen:";
lblObjekt.Text = "Object:";
lblRechnungsNr.Text = "Nr. dil quen:";
lblRechnungsdatum.Text = "Datum da quen:";
lblERechnungsID.Text = "ID";
lblAbonnent.Text = "Abonnent";
}
Is not well suited for that. I have been asked to create options for I18n support. Quoted from the AR11 documentation:
To localize a Report at design time
1. Click the gray area around the design surface to select the Report in the Properties window.
2. In the Properties window, drop down the Culture or Language property and select the culture that you want to apply to the report.
The old default was: (default, inherit), I know changed that to German (Switzerland). I couldn't find any difference, no new stuff under C:\Program Files (x86)\GrapeCity\ActiveReports 11\Localization, nor elsewhere in the xml.
How do I add a new language sheet / values for the current report and it's labels?
How do I add a culture that does not exist yet? (In worst case I'd use any local and use it as romansh, since only german, italian, french and unlikely english could be used)
The Language property, mentioned in the documentation, works for the code-based templates only. When you set the new language by this property VSID creates the additional resource file, e.g. myreport.jp-JP.resx.
In such case, the compiled report will upload the needed resources according to CurrentThread.CurrentUICulture value. It does not work for RPX(xml-based) templates.
So if you want to use this functionality, you need to convert xml-based to code-based templates.
The Culture property helps only to specify a locale for OutputFormat feature(e.g. conversion to currency).
For RPX templates localization, I think you could combine the external localization resource files with the current scripting approach, I mean the loading of the resource file in script and update the report items.
Thanks,
I'm developing a Firefox extension that involves dictionaries in various languages and dialects. I want to display a dialog to the user to select spell checking dictionaries for the available languages.
It will be tedious for the user to select from values like en-US, ar-EG, en-GB, etc., so, I want to display the localized language names like what Firefox does in this screenshot
This is the dictionary selection menu on my Arabic Firefox displaying the names of the two languages en-US and ar.
How to do such thing?
Here is what I did to find and use these strings:
1- I downloaded the whole Firefox source code and extracted it.
2- I searched the source files for the name "New Zealand". This unique country name should exist only in the file I'm looking for. Rather than using general terms like English, United States, Arabic, etc.
3- The search led me to two interesting files: regionNames.properties and languageNames.properties. The first has the names of all countries and the other has the names of all languages. Firefox should be using the two sets of strings to display dictionary names.
4- I found that the two files can be fetched from the URLs chrome://global/locale/languageNames.properties and chrome://global/locale/regionNames.properties, so, I used the string bundle service and the string bundle objects to load and use the resources.
Here's a code sample:
On the top of my main.js file:
const {Cc, Ci, Cu} = require("chrome"),
stringBundles = Cc["#mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService);
Then I have this piece of code in another method:
let languagesNamesBundle = stringBundles.createBundle("chrome://global/locale/languageNames.properties"),
countriesNames = stringBundles.createBundle("chrome://global/locale/regionNames.properties");
console.log(languagesNamesBundle.GetStringFromName("ar")); // العربية Arabic
console.log(languagesNamesBundle.GetStringFromName("af")); // الأفريكانية Afrikaans
console.log(countriesNames.GetStringFromName("fj")); // فيجي Fiji
console.log(countriesNames.GetStringFromName("cr")); // كوستا ريكا Costa Rica
And this is what I wanted. Now I can compose dictionary names from languages and countries names.
I'll update the answer to add the path of the project repository after I publish the final result.
This is very easily doable. I have some very basic templates for localization here:
https://github.com/Noitidart/l10n/tree/xhtml-xul
https://github.com/Noitidart/l10n/tree/properties
properties files are for within privelaged js file localiztion. and .dtd is used for xul/xhtml/and inline javascript.
Is there a reliable way to identify the filetype of a file across Windows platforms?
I've inherited a program which queries filetypes using the Shell32 GetDetailsOf function, which returns localized strings and causes an error if a non-english system is used (for example, on a german system GetDetailsOf(item,9) returns "Bild" instead of "Image").
Using the textual description of a filetype is not a reliable way of identifying particular types of file. As you've noticed the description strings change from language to language, but they can also change within the one language depending on the software the user has installed (as a made up example, a .jpg file might have the description "JPEG image" on one system, and "Adobe Photoshop Image" on another system if the user has installed software that claims the filetypes and changes the description).
Instead, your best way of identifying the filetype is to look at the file's extension (.jpg in our example). What you do with it then is up to you and depends on your application. You might just have a hard-coded list of extensions that you work with, or to be more generic you could look in the registry for the filetype's "perceived type":
HKEY_CLASSES_ROOT\.jpg\PerceivedType
To see if that value is set to "image", "audio", etc.
We have a number of MFC extension dlls in our code base, many of which have embedded Windows resources defined in the projects .rc files (IDS_..., IDD_..., IDB_... etc). We use numerical identifiers to define our resources, taking special care that our resource ids don't clash across dlls, which requires some management to ensure our developers don't use the same numberings.
I've realised that string-type resource identifiers might be an easy way to go, meaning that we can define unique identifiers for each resource in each different dll.
My question is, are there any technical problems with doing this, for example:
Will the MFC dll / resource chain still function correctly?
Will the Visual Studio resource editor still work?
I haven't found anything in the MS Technical Notes to say this would be a problem - I'd just wondering if people have had experience with this.
Note however that IDs of strings in the string table (IDS_) MUST be numeric (16 bits IIRC). The difference between a string and another resource is due to strings not being individual resources. Actually, the string table consists in a set of resources, each containing up to 16 strings with consecutive IDs.
Same goes for Control IDs within dialogs. But you most likely know that.
In the resource editor, you can specify a string resource id in the property grid by simply putting quotes around the resource names.
Regarding dialogs and the resource editor: You'll have a minor problem: Whenever you create a class for the dialog, the generated code contains enum { IDD = resourceid }. Needless to say that it won't work for a string id. But you can easily get rid of this IDD enum and replace it by a string.
We do have a website which should be translate into different languages. Some of the wording is in message properties files ready for translation. I want now add the rest of the text into these files.
What is a good way to name the text blocks?
<view>.<type>.<name>
We mostly have webpages and some of the elements/modules are repeating on some sites.
As far as I know, no "standard" exists. Therefore it is pretty hard to tell what is proper and what is improper way of naming resource keys. However, based on my experience, I could recommend this way:
property file name: <module>.properties
resource keys: <view or dialog>[.<sub-context>].<control-type>.<name>
We may discuss if it is proper way to put every strings from one module into one property files - probably it could be right if updates doesn't happen often and there are not so many messages. Otherwise you might think about one file per view.
As for key naming strategy: it is important for the Translator (sounds like film with honorable governor Arnold S. isn't it?) to have a Context. Translation may actually depend on it, i.e. in Polish you would translate a message in a different way if it is page/dialog/whatever title and in totally different way if it is text on a button.
One example of such resource key could be:
preferences.password_area.label.username=User name
It gives enough hints to the Translator about what it actually is, which could result in correct translation...
We have come up with the following key naming convention (Java, btw) using dot notation and camel case:
Label Keys (form labels, page/form/app titles, etc...i.e., not full sentences; used in multiple UI locations):
If the label represents a Java field (i.e., a form field) and matches the form label: label.nameOfField
Else: label.sameAsValue
Examples:
label.firstName = First Name
label.lastName = Last Name
label.applicationTitle = Application Title
label.editADocument = Edit a Document
Content Keys:
projectName.uiPath.messageOrContentType.n.*
Where:
projectName is the short name of the project (or a derived name from the Java package)
uiPath is the UI navigation path to the content key
messageOrContentType (e.g., added, deleted, updated, info, warning, error, title, content, etc.) should be added based on the type of content. Example messages: (1) The page has been updated. (2) There was an error processing your request.
n.* handles the following cases: When there are multiple content areas on a single page (e.g., when the content is separated by, an image, etc), when content is in multiple paragraphs or when content is in an (un)ordered list - a numeric identifier should be appended. Example: ...content.1, ...content.2
When there are multiple content areas on a page and one or more need to be further broken up (based on the HTML example above), a secondary numeric identifier may be appended to the key. Example: ...content.1.1, ...content.1.2
Examples:
training.mySetup.myInfo.content.1 = This is the first sentence of content 1. This is the second sentence of content 1. This content will be surrounded by paragraph tags.
training.mySetup.myInfo.content.2 = This is the first sentence of content 2. This is the second sentence of content 2. This content will also be surrounded by paragraph tags.
training.mySetup.myInfo.title = My Information
training.mySetup.myInfo.updated = Your personal information has been updated.
Advantages / Disadvantages:
+ Label keys can easily be reused; location is irrelevant.
+ For content keys that are not reused, locating the page on the UI will be simple and logical.
- It may not be clear to translators where label keys reside on the UI. This may be a non-issue for translators who do not navigate the pages, but may still be an issue for developers.
- If content keys must be used in more than one location on the UI (which is highly likely), the key name choice will not make sense in the other location(s). In our case, management is not concerned with a duplication of values for content areas, so we will be using different keys (to demonstrate the location on the UI) in this case.
Feedback on this convention - especially feedback that will improve it - would be much appreciated since we are currently revamping our resource bundles! :)
I'd propose the below convention
functionalcontext.subcontext.key
logicalcontext.subcontext.key
This way you can logically group all the common messages in a super context (id in the below example). There are few things that aren't specific to any functional context (like lastName etc) which you can group into logical-context.
order.id=Order Id
order.submission.submit=Submit Order
name.last=Last Name
the method that I have personally used and that I've liked more so far is using sentence to localisee as the key. For example: (pls replace T with the right syntax dependably on the language)
for example:
print(T("Hello world"))
in this case T will search for a key "Hello world". If it is not found then the key is returned, otherwise the value of the key.
In this way, you do not need to edit the message (in your default language) at least that you need to use parameters.... It saved me a LOT of dev time