One of the non-trivial task that can be given to a developer is the report localization. In other words - creation of multilingual reports. What does it mean?
For different languages the same report template is applied. Language header and data can be specified by user or a program.
Such reports are in demand in global market companies. Besides that, automation of template translation into different languages will facilitate further support of complex reports and eliminate the need to store templates for each language.
Report localization would be easy for programmers using FastReport .NET reporting tool.
So, what are the ways to solve this problem?
1. The user application transfers headers or data for the report in the desired language by parameters;
2. All of the fields that need to be localized are added to the database. Each row in the table will contain the data in a particular language. The report uses fields of the table in headers that need to be localized. All that's left to do is to choose the desired language.
Both ways have their advantages and disadvantages.
In the first case, with increasing amounts of data that needs to be localizes, the amount of code in the user application is increasing as well. But instead it does not require creating of a separate database or tables in an existing one. Such method is more suitable for a small amount of localized data.
In the second case, all the data is stored in the database and not in user application's code. The table from the database is convenient to scale and add new data. But it's necessary to create a separate table, connection to it and a certain amount of code in the report script. Such method is better for large volumes of localized data.
Let's look at the two suggested ways in practice:
Creating a report.
3. Double-click on the added component report1. Close the form of the data source. The report designer is run.
4. Invoice type of report has been selected to demonstrate localization. Here we need to localize all the titles and labels. Customer and product data will be taken from the sample database (nwind.xml), which comes with FastReport .NET.
5. Create the connection to the data nwind.xml. And choose the 4 tables: Orders, Order Detail, Customers, Products.
6. In order to demonstrate the first method of localization, we need to create a number of report parameters.
Each header or label in the report should be replaced with the appropriate parameters:
As you can see from the figure, all the headers presented by the report parameters.
Parameters can be set to the default in case you do not want to pass some of them. For this purpose use the property Expression of the parameter. Text value is given in double quotes. For example, setting pOurCompany default "Fast Reports Inc."
7. For demonstration of the second method, we need a table that contains the same fields as in the report parameters and the data in the three languages.
We use, for example, a Microsoft Access database.
Field name |
Data type |
Id |
Counter |
pInvoice |
Text |
pOurCompany |
Text |
pOurCompanyAddress |
Text |
pOurCompanyPhone |
Text |
pCustomerId |
Text |
pCustomerCompany |
Text |
pCustomerName |
Text |
pCustomerAddress |
Text |
pCustomerPostalCode |
Text |
pCustomerPhone |
Text |
pCustomerFax |
Text |
pCurrency |
Text |
pProductName |
Text |
pQuantity |
Text |
pUnitPrice |
Text |
pAmount |
Text |
pTotal |
Text |
pSignature |
Text |
pName |
Text |
pDate |
Text |
pLang |
Text |
pAgree |
Text |
And fill the table:
8. Add another data source in the report. Select created in the Access database.
9. Now, in the report script you should assign the values from the Localization table fields to the report parameters. Create StartReport event:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
private void _StartReport(object sender, EventArgs e) { string lang =(string)Report.GetParameterValue("pLang"); DataSourceBase ds=Report.GetDataSource("Localization"); ds.Init(); while (ds.HasMoreRows) { string val=(string)Report.GetColumnValue("Localization.pLang"); if (val==lang) { Report.SetParameterValue("pInvoice", (string)Report.GetColumnValue("Localization.pInvoice")); Report.SetParameterValue("pOurCompany", (string)Report.GetColumnValue("Localization.pOurCompany")); Report.SetParameterValue("pOurCompanyAddress", (string)Report.GetColumnValue("Localization.pOurCompanyAddress")); Report.SetParameterValue("pOurCompanyPhone", (string)Report.GetColumnValue("Localization.pOurCompanyPhone")); Report.SetParameterValue("pCustomerId", (string)Report.GetColumnValue("Localization.pCustomerId")); Report.SetParameterValue("pCustomerCompany", (string)Report.GetColumnValue("Localization.pCustomerCompany")); Report.SetParameterValue("pCustomerName", (string)Report.GetColumnValue("Localization.pCustomerName")); Report.SetParameterValue("pCustomerAddress", (string)Report.GetColumnValue("Localization.pCustomerAddress")); Report.SetParameterValue("pCustomerPostalCode", (string)Report.GetColumnValue("Localization.pCustomerPostalCode")); Report.SetParameterValue("pCustomerPhone", (string)Report.GetColumnValue("Localization.pCustomerPhone")); Report.SetParameterValue("pCustomerFax", (string)Report.GetColumnValue("Localization.pCustomerFax")); Report.SetParameterValue("pCurrency", (string)Report.GetColumnValue("Localization.pCurrency")); Report.SetParameterValue("pProductName", (string)Report.GetColumnValue("Localization.pProductName")); Report.SetParameterValue("pQuantity", (string)Report.GetColumnValue("Localization.pQuantity")); Report.SetParameterValue("pUnitPrice", (string)Report.GetColumnValue("Localization.pUnitPrice")); Report.SetParameterValue("pAmount", (string)Report.GetColumnValue("Localization.pAmount")); Report.SetParameterValue("pTotal", (string)Report.GetColumnValue("Localization.pTotal")); Report.SetParameterValue("pSignature", (string)Report.GetColumnValue("Localization.pSignature")); Report.SetParameterValue("pName", (string)Report.GetColumnValue("Localization.pName")); Report.SetParameterValue("pDate", (string)Report.GetColumnValue("Localization.pDate")); Report.SetParameterValue("pAgree", (string)Report.GetColumnValue("Localization.pAgree")); } ds.Next(); } } |
In the first line of code, we get the value of the parameter pLang. Looking ahead, I'll say that this parameter contains the ID of the selected language in the program.
Then we get the source Localization of data to find the record for the selected language in the cycle.
After that we assign the values from the table to the report parameters.
The report is ready. Save it.
Create app
Add the two switches, drop-down list and a couple of buttons to the form.
Add the three languages in the drop-down list:
The main application code is invoked when you click Show report:
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
using (Report report = new Report()) { report.Load(Environment.CurrentDirectory + "\\Invoice.frx"); // Here begins the code responsible for the first method of localization if ((radioButton1.Checked) && (LanguagesCmdBox.SelectedIndex == 0)) { report.SetParameterValue("pInvoice", "Invoice"); report.SetParameterValue("pOurCompany", "FastReports Inc"); report.SetParameterValue("pOurCompanyAddress", "US Alexandria VA 22314"); report.SetParameterValue("pOurCompanyPhone", "Phone: 800-985-8986"); report.SetParameterValue("pCustomerId", "Customer Id:"); report.SetParameterValue("pCustomerCompany", "Company:"); report.SetParameterValue("pCustomerName", "Name:"); report.SetParameterValue("pCustomerAddress", "Address:"); report.SetParameterValue("pCustomerPostalCode", "Postal Code: "); report.SetParameterValue("pCustomerPhone", "Phone:"); report.SetParameterValue("pCustomerFax", "Fax:"); report.SetParameterValue("pCurrency", "Currency: $"); report.SetParameterValue("pProductName", "Product Name"); report.SetParameterValue("pQuantity", "Quantity"); report.SetParameterValue("pUnitPrice", "Unit Price"); report.SetParameterValue("pAmount", "Amount"); report.SetParameterValue("pTotal", "Total"); report.SetParameterValue("pSignature", "Signature"); report.SetParameterValue("pName", "Name"); report.SetParameterValue("pDate", "Date"); report.SetParameterValue("pAgree", "I declare that the above information is true and correct to the best of my knowledge"); } if ((radioButton1.Checked) && (LanguagesCmdBox.SelectedIndex == 1)) { report.SetParameterValue("pInvoice", "Счет"); report.SetParameterValue("pOurCompany", "ООО Фаст Репортс"); report.SetParameterValue("pOurCompanyAddress", "Россия, Ростов-на-Дону"); report.SetParameterValue("pOurCompanyPhone", "Телефон: +7(863)227-07-40"); report.SetParameterValue("pCustomerId", "Идентификатор:"); report.SetParameterValue("pCustomerCompany", "Компания:"); report.SetParameterValue("pCustomerName", "Имя:"); report.SetParameterValue("pCustomerAddress", "Адрес:"); report.SetParameterValue("pCustomerPostalCode", "Индекс:"); report.SetParameterValue("pCustomerPhone", "Телефон:"); report.SetParameterValue("pCustomerFax", "Факс:"); report.SetParameterValue("pCurrency", "Валюта: руб"); report.SetParameterValue("pProductName", "Наименование"); report.SetParameterValue("pQuantity", "Количество"); report.SetParameterValue("pUnitPrice", "Цена"); report.SetParameterValue("pAmount", "Подитог"); report.SetParameterValue("pTotal", "Итого"); report.SetParameterValue("pSignature", "Подпись"); report.SetParameterValue("pName", "ФИО"); report.SetParameterValue("pDate", "Дата"); report.SetParameterValue("pAgree", "Я объявляю, что вышеупомянутая информация верна и правильна насколько я знаю"); } if ((radioButton1.Checked) && (LanguagesCmdBox.SelectedIndex == 2)) { report.SetParameterValue("pInvoice", "Rechnung"); report.SetParameterValue("pOurCompany", "Fast Reports Inc"); report.SetParameterValue("pOurCompanyAddress", "US Alexandria VA 22314"); report.SetParameterValue("pOurCompanyPhone", "Telefon: +4930568373928"); report.SetParameterValue("pCustomerId", "Kundennummer:"); report.SetParameterValue("pCustomerCompany", "Unternehmen:"); report.SetParameterValue("pCustomerName", "Name:"); report.SetParameterValue("pCustomerAddress", "Anschrift:"); report.SetParameterValue("pCustomerPostalCode", "Postleitzahl:"); report.SetParameterValue("pCustomerPhone", "Telefon:"); report.SetParameterValue("pCustomerFax", "Faxen:"); report.SetParameterValue("pCurrency", "Währung: eur"); report.SetParameterValue("pProductName", "Produktname"); report.SetParameterValue("pQuantity", "Menge"); report.SetParameterValue("pUnitPrice", "Stückpreis"); report.SetParameterValue("pAmount", "Höhe"); report.SetParameterValue("pTotal", "Gesamt"); report.SetParameterValue("pSignature", "Signatur"); report.SetParameterValue("pName", "Name"); report.SetParameterValue("pDate", "Datum"); report.SetParameterValue("pAgree", "Ich erkläre, dass die oben genannten Informationen wahr und korrekt auf die nach meinem besten Wissen"); } // Here begins the code responsible for the second method of localization if (radioButton2.Checked) { switch (LanguagesCmdBox.SelectedIndex) { case 0: report.SetParameterValue("pLang", "En"); break; case 1: report.SetParameterValue("pLang", "Ru"); break; case 2: report.SetParameterValue("pLang", "De"); break; } } |
Let's look at the code in close-up. As you can see, it is divided by a comment on the two blocks - the first method and the second method of localization. Initially, the developed earlier report is loaded.
Next, there is a check point on which method of localization is selected. And also there is a check point on which language of localization is selected. Three conventional designs for the three languages. There is assigning values to parameters of the report within each condition. The method SetParametrValue has two parameters: the name of the report parameter and its value. Thus, we fill all the parameters values in the selected language.
The second method uses a similar localization conditional constructions. But inside only one parameter of the report is defined - pLang - selected language. Having this parameter, the report will select necessary record from the localization tables.
There is another advantage of this method, which was not mentioned at the beginning. It can be stored database localizations (Localization) within the report to facilitate its subsequent maintenance and exclusion of additional data source. To do this, select the Localization table in the data tree and set property StoreData = True. The table is saved in the report template. In this case it will be possible to skip the setting of one of the bases in the program. However, there is one disadvantage of using a stored database (tables) - if you want to add new fields to a data source you will need to reconnect to the source table.
So, we have considered two ways of localization a report in FastReport .Net. Which way is better - it's a developer choice, it depends on the individual case. Next will be the results of the work done - three reports in different languages.
In English:
And in German: