Unicode Support from NAV
3.10 to NAV 2009
Microsoft Issues
- The double-byte character
set, code page ‘XXX’ à (ex: 932 Japanese), is
not supported by this version of Microsoft Dynamics NAV: Microsoft Dynamics NAV
2009, Microsoft Dynamics NAV 5.0, Microsoft Dynamics NAV 4.0, Microsoft
Business Solutions–Navision 3.70, Navision Attain 3.6, or Navision Attain 3.10.
- Supported only on NAV 2013, native support
Double-Byte Character Set (DBCS) code page error when you start Microsoft Dynamics NAV
- It is known that NAV CC
(Classic Client) does not support natively DBCS (Double-Byte Character Set) and so does the
new NAV 2009 RTC (Roled Tailored Client)
- Due to differences in how
the CC and RTC check the code page isn’t still possible to
enable DBCS in the RTC but this is possible for the CC by implementing new fin.stx file.
Workaround
to handle unicode chars
How to enable and to display
double-byte character sets in Microsoft Dynamics NAV https://mbs.microsoft.com/knowledgebase/KBDisplay.aspx?scid=kb;EN-US;915374
WHAT TYPE
OF ENCODING?
Roughly
speaking regarding what we have done is merely enabling theJ apanese
characters to be stored into SQL Server but… not directly!
The Japanese code page is 932 (Shift-JIS) while
we are using the Latin1 code page 1252 to
store the data. To know
more about Windows
Collation Designators you can check: http://msdn.microsoft.com/en-s/library/aa176553.aspx
This
means that while we are typing Japanese chars in the NAV classic Client
(using code page 932), this have been reverted
(translation encoded) in their respective characters using code page 1252 and stored in this way in the SQL Server field.
This means that while we
are seeing this in NAV :
Support
- Note XXXX (ex. 932) is the placeholder for the one of the
following code pages: http://msdn.microsoft.com/en-us/library/aa176553.aspx
932: Japanese Shift-JIS
936: Simplified Chinese GBK 949: Korean 950: Traditional Chinese Big5
- All
windows languages are supported
SOLUTION
- Then the solution can come out clearly: use C# encoding function to manage the ‘translation’ between one set of character to another.
SUPPORTO LINGUE CINESE TRADIZIONALE, GIAPPONESE etc.
SPIEGAZIONE SUPPORTO UNICODE PER NAV 2009 e NAV 2013
NAV 2009 non supporta unicode
NAV 2013 supporta unicode nativo
NAV 2013 Sample
On Page Chin2 field is visible with Chinese Char
Unicode & Chinese Data
NAV 2009 Sample, Classic Client
Only unicode, no Chinese
Cosa significa:
Se sarebbe già possibile (con la modifica sopra illustrata) inserire un dato in cinese (es: su Word) ciò non è sarebbe possibile su NAV in quanto il client non riconosce i caratteri e li scrive in formato “?????????”
In pratica NAV (e SQL Server) non riescono a memorizzare il dato in cinese anche se sembra che possa essere inserito
Su un database SQL Server (con collaction CS o CI latin general_1) non è possibile inserire caratteri cinesi (non li fa scrivere nel db, mette ‘???????’ unknow data value)
Le possibilità di gestione sarebbero 3:
1 - Creare e scrivere direttamente in un db cinese (chinese collaction) > è un nuovo db NAV\SQL
2 - Convertire il db attuale in unicode support (raddoppia lo spazio su disco, rallenta il database, non sappiamo quanto ci metterebbe a convertirlo, potrebbe non convertire il tutto e bloccarsi durante la conversione; gestirebbe correttamente la scrittura del dato cinese sul db ma non lo potrebbe visualizzare comunque in NAV (cioè scrive nel db ma non visualizza in NAV)
3 - Modificare il db attuale modificando un parametro che permetta di inserire il dato in formato unicode metadato (cioè non in cinese ma nel suo unicode) dicendo a SQL di non scartare il dato; con questa soluzione in sostanza potremmo importare dati da file esterni : TXT, XLS in unicode format su SQL
Gestirebbe correttamente la scrittura del metadato unicode (creato da alcune procedure di Codifica\Decodifica da installare basate su windows) che rappresenta il cinese ; non lo potrebbe visualizzare comunque in NAV (cioè scrive nel db un dato che potremmo OnDemand convertire in cinese ma non visualizza in NAV)
Soluzione meno invasiva
“Opzione 3”
Cosa si può fare:
Supportiamo la scrittura del metadato sul database (unicode corrispondente al cinese)
E’ possibile caricare tramite batch input (file TXT, XLS salvato in unicode) nel database
E’ possibile creare ed esporre delle viste che visualizzano sia il metadato che la lingua cinese (da esporre al web)
E’ possibile dal web scrivere il metadato di ritorno al db utilizzando le stesse funzioni usate
Come funziona: tramite 2 funzioni custom su SQL viene fatto Encode \ Decode del dato per permettere di scrivere \ leggere il dato in unicode e di visualizzarlo in cinese.
Come lo facciamo:
Visualizzazione, esposizione dati, importazione\esportazione dati
Modifica ed aggiunta dati: - Per visualizzare i dati in cinese (o modificarli \ aggiungerli etc.) è necessario creare alcune “Windows Forms” da lanciare da Nav per visualizzare\modificare i dati; queste maschere sembrano NAV ma son NAV; sono fatte in Visual Studio. Sarà possibile aggiungere dati salvando in metadati ma visualizzando in cinese
Esposizione dati per Web: - Saranno create delle viste SQL che richiamando le funzioni Encode \ Decode e visualizzeranno in dati in cinese
Es: Vista con dati unicode
/****** Script for SelectTopNRows command from SSMS ******/
SELECT TOP 1000 [Code]
,[DescrReconverted]
,[Descr]
,[Chinese]
FROM [Demo Database NAV (7-0)].[dbo].[CRONUS Italia S_p_A_$V_ART_CINESE_NAV]
Descr = METADATO (unicode), Chinese = dati in cinese (trascodificato da procedura)
Import\Export dati: Saranno creati dei DTS che utilizzando i sistemi di codifica visti sopra permetteranno l’inserimento del metadato unicode.
ES SQL DTSX: COMPLETE FLOW
FLAT FILE (OR UNICODE OR CHINESE COLLACTION TABLE)
OBJECT SCRIPT
Ø Lo script component converte il dato NAV da Chinese in unicode e lo scrive su SQL in unicode (cosa non possibile da NAV)
Ø Input Columns (unicode data from SQL Unicode Table or Unicode TXT or EXCEL files)
DT_WSTR > double bytes for Chinese chars
Output Columns (string format to handle unicode data DT_STR)
C# code in Script Component
/* Help: Introduction to the Script Component */
/* The Script Component allows you to perform virtually any operation that can be accomplished in a .Net application within the context of an Integration Services data flow.
* Expand the other regions which have "Help" prefixes for examples of specific ways to use
* Integration Services features within this script component. */
Namespaces
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime.Wrapper;
using System.Text;
// RS, 20130531, Encode\Decode Integrated Script (C#)
// This is the class to which to add your code. Do not change the name, attributes, or
// parent of this class.
[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
{
Help: Using Integration Services variables and parameters
* Example of reading from a variable or parameter:
* DateTime startTime = Variables.MyStartTime;
*
* Example of writing to a variable:
* Variables.myStringVariable = "new value";
*/
Help: Using Integration Services Connnection Managers
*
* If the component needs to hold a connection open while processing rows, override the
* AcquireConnections and ReleaseConnections methods.
*
* Example of using an ADO.Net connection manager to acquire a SqlConnection:
* object rawConnection = Connections.SalesDB.AcquireConnection(transaction);
* SqlConnection salesDBConn = (SqlConnection)rawConnection;
*
* Example of using a File connection manager to acquire a file path:
* object rawConnection = Connections.Prices_zip.AcquireConnection(transaction);
* string filePath = (string)rawConnection;
*
* Example of releasing a connection manager:
* Connections.SalesDB.ReleaseConnection(rawConnection);
*/
Help: Firing Integration Services Events
/* This script component can fire events.
*
* Example of firing an error event:
* ComponentMetaData.FireError(10, "Process Values", "Bad value", "", 0, out cancel);
*
* Example of firing an information event:
* ComponentMetaData.FireInformation(10, "Process Values", "Processing has started", "", 0, fireAgain);
*
* Example of firing a warning event:
* ComponentMetaData.FireWarning(10, "Process Values", "No rows were received", "", 0);
*/
///
/// This method is called once, before rows begin to be processed in the data flow.
/// You can remove this method if you don't need to do anything here.
///
Public override void PreExecute()
{
base.PreExecute();
/*
* Add your code here
*/
}
/// This method is called after all the rows have passed through this component.
///
/// You can delete this method if you don't need to do anything here.
Public override void PostExecute()
{
base.PostExecute();
/*
* Add your code here
*/
}
/// This method is called once for every row that passes through the component from
// Input0.
/// Example of reading a value from a column in the the row:
/// string zipCode = Row.ZipCode
///
/// Example of writing a value to a column in the row:
/// Row.ZipCode = zipCode
Public override void Input0_ProcessInputRow(Input0Buffer Row)
{
/*
* Add your code here
*/
// Create a new variable of type Encoding and
// assign it the Latin *** code page 1252 ***
// To know more about it
// http://msdn.microsoft.com/en-us/library/system.text.encoding_members.aspx
Encoding nav = Encoding.GetEncoding(1252);
// Create a new variable of type Encoding and assign it the Japanese
// *** Code page 932 Japanese
// Encoding unicode = Encoding.GetEncoding(932);
Encoding unicode = Encoding.GetEncoding(936);
// Assign Rowdata Values
byte[] unicodeCod = unicode.GetBytes(Row.Cod);
byte[] unicodeDescription = unicode.GetBytes(Row.Description);
byte[] reconverted = nav.GetBytes(Row.Description);
// Assign Added Output Fields
this.Output0Buffer.AddRow();
Output0Buffer.CodNav = nav.GetString(unicodeCod);
Output0Buffer.DescriptionNav = nav.GetString(unicodeDescription);
Output0Buffer.Reconverted = unicode.GetString(reconverted);
// **
// ComponentMetaData.FireInformation(10, "Process Values",
unicode.GetString(reconverted), "", 0, true);
// Row.Cod = nav.GetString(unicodeCod);
// Row.Description = nav.GetString(unicodeDescription);
// **
}
}
SQL Destination Preview
Code = converted from Chiese to Unicode
Descr = converted from Chiese to Unicode
Cosa non si può fare nel db attuale (non unicode e non in cinese):
Su Nav non è possibile visualizzare i dati i cinese dal client classic > ‘???????’
Non è possibile stampare il documento in cinese (stesso problema del client) > ‘???????’
Non è possibile fatturare in cinese (e contabilizzare fatture in cinese)
Se servisse fatturare su NAV occorre creare un “DB Cinese”
Importare tramite viste sql e stored procedures i dati dal db attuale sul db cinese trascodificando tramite le funzioni sopra descritte e scrivendo il dato in cinese
Non è possibile eseguire una fatturazione in NAV poiché ci sono dei vincoli nelle localizzazioni cinesi, giapponesi etc.; sulla cinese viene messo un oggetto che collegato al tel. stacca il protocollo di fatturazione cinese che deve validare le fatture
SUPPORT UNICODE IN NAV – PROCEDURA
WINDOWS INPUT DATA
Come indicato nella documentazione Microsoft, Dynamics NAV 2009 non è direttamente abilitato all’utilizzo diretto dei caratteri Unicode. Il sistema operativo(windows) permette di utilizzare i caratteri Unicode anche per la visualizzazione e l’inserimento dei dati con programmi non abilitati utilizzando una particolare impostazione del menu [Region and Language] in ITA [Paese e Lingua] (in questo documento facciamo riferimento ad un client Windows 7). Si suppone che il computer sia già impostato per utilizzare i caratteri cinesi.
MODIFICHE WINDOWS
Come si imposta:
L’impostazione è [Language for non-Unicode programs], che si trova nel tab [Advanced] di [Region and Language]:
Dal menu visualizzato, selezionare Chinese Simplified, PRC,oppure Chinese Traditional (es: Taiwan). Questa impostazione richiede il riavvio del pc.
Fatta questa prima modifica, il client è abilitato all’inserimento dei caratteri Unicode in Dynamics NAV; lo farebbe però solo su un db con collaction cinese
MODIFICA A PARAMETRO NAV (su SQL SERVER) per SUPPORT INPUT UNICODE DATA
Prima di poter effettivamente utilizzare questa caratteristica, è necessario modificare un parametro del server Dynamics NAV che se impostato impedisce l’inserimento nel database di caratteri non compatibili con la collation indicata per il database SQL: per modificare questo parametro è necessario impostare il database in Single User Mode (), effettuare la modifica ed uscire dal Single User Mode.
Il campo [Convalida regole di confronto] in [Confronto] deve essere impostato a FALSE
Cosa fa questo flag : permette a NAV di scrivere i dati senza chiedere la validazione della collaction SQL Server (bypass input)
Gli altri parametri di questa pagina non devono essere modificati.
MY TEST CASE
La principale difficoltà segnalata da Microsoft Italia era relativa all’impossbilità di inserire direttamente i caratteri cinesi nel database Dynamics NAV, in quanto i campi rimangono di tipo VARCHAR mentre i campi contenenti dati Unicode sono di tipo NVARCHAR. Ne deriva che un dato visualizzato in Dynamics NAV come scritto con caratteri cinesi (due bytes) viene in effetti salvato nel database nelle sue componenti costitutive in byte.
Poiché sono presenti alcune procedure di scambio automatico dei dati, è stata implementata nell’ambiente di sviluppo e test una possibile soluzione per questo problema.
Si tratta di una serie di metodi esposti da una classe scritta in C# per .NET 3.5, che forniscono le funzionalità di conversione dalla codifica Unicode cinese e giapponese verso la codifica utilizzata da Dynamics NAV, e viceversa.
Per installare ed utilizzare queste funzioni è necessario abilitare il server nel quale verranno richiamate le funzioni all’utilizzo di CLR, mediante i seguenti comandi:
Da console SQL (new query)
-- attivazione CLR per supporto Assembly --
sp_configure 'clr enable', 1
GO
RECONFIGURE
GO
Codeunit Parser “UnicodeConverter.dll”
Cosa fa: gestisce la trascodifica unicode tramite DLL Windows
Copiare la DLL UnicodeConverter.dll nella cartella del server SQL (normalmente in C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\Binn\) per l’utilizzo in SQL, tramite il comando
Da console SQL Server (new query)
C# Code per DLL
// ** Code, Encode ** /
// ** RS, 20130531 ** /
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using Microsoft.SqlServer.Server;
using System.Data.SqlTypes;
using System.Text;
// PUBLIC CLASS ** CONVERTER **
public class Converter
{
[SqlFunction(IsDeterministic = true)]
public static SqlString Chinese2NAV(SqlString ChineseString)
{
/* Encode es: 1252 Non Unicode*/
Encoding NotUnicode = Encoding.GetEncoding(1252);
/* Encode es: 936 Unicode*/
Encoding Chinese = Encoding.GetEncoding(936);
return (NotUnicode.GetString(Chinese.GetBytes((string)ChineseString)));
}
[SqlFunction(IsDeterministic = true)]
public static SqlString NAV2Chinese(SqlString NotUnicodeString)
{
/* Encode es: 1252 Non Unicode*/
Encoding NotUnicode = Encoding.GetEncoding(1252);
/* Encode es: 936 Chinese*/
Encoding Chinese = Encoding.GetEncoding(936);
// Return Chinese
return (Chinese.GetString(NotUnicode.GetBytes((string)NotUnicodeString)));
}
[SqlFunction(IsDeterministic = true)]
public static SqlString Japanese2NAV(SqlString JapaneseString)
{
/* Encode es: 1252 Non Unicode*/
Encoding NotUnicode = Encoding.GetEncoding(1252);
/* Encode es: 932 Chinese*/
Encoding Japanese = Encoding.GetEncoding(932);
return (NotUnicode.GetString(Japanese.GetBytes((string)JapaneseString)));
}
[SqlFunction(IsDeterministic = true)]
public static SqlString NAV2Japanese(SqlString NotUnicodeString)
{
/* Encode es: 1252 Non Unicode*/
Encoding NotUnicode = Encoding.GetEncoding(1252);
/* Encode es: 932 Chinese*/
Encoding Japanese = Encoding.GetEncoding(932);
// Return Japanese
return (Japanese.GetString(NotUnicode.GetBytes((string)NotUnicodeString)));
}
}
REGISTRAZIONE ASSEMBLY PER DLL SU SQL SERVER
Registrazione DLL ‘UnicodeConverter.dll'
CREATE ASSEMBLY UnicodeConverter from 'C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\Binn\UnicodeConverter.dll' WITH PERMISSION_SET = SAFE
Mio test case:
-- attivazione CLR per supporto Assembly --
sp_configure 'clr enable', 1
GO
RECONFIGURE
GO
-- Creazione ASSEBLY per pubblicare la DLL a SQL --
CREATE ASSEMBLY UnicodeConverter from 'C:\Program Files\Microsoft SQL Server\MSSQL10_50.SQL2008R2\MSSQL\Binn\UnicodeConverter.dll' WITH PERMISSION_SET = SAFE
Infine devono essere create le funzioni su SQL utente da richiamare per la conversione:
CREATE Function Chinese2NAV(@matchString nvarchar(max)) returns nvarchar(max)
AS EXTERNAL NAME UnicodeConverter.Converter.Chinese2NAV
CREATE Function Japanese2NAV(@matchString nvarchar(max)) returns nvarchar(max)
AS EXTERNAL NAME UnicodeConverter.Converter.Japanese2NAV
CREATE Function NAV2Chinese(@matchString nvarchar(max)) returns nvarchar(max)
AS EXTERNAL NAME UnicodeConverter.Converter.NAV2Chinese
CREATE Function NAV2Japanese(@matchString nvarchar(max)) returns nvarchar(max)
AS EXTERNAL NAME UnicodeConverter.Converter.NAV2Japanese
Queste funzioni potranno quindi essere utilizzate per la scrittura e la lettura dei dati nel formato Dynamics NAV.
Si noti che queste funzioni convertono le stringhe senza porre limitazioni circa la lunghezza della stringa stessa: devono quindi essere verificate e confrontate rispetto alla lunghezza effettiva dei campi disponibili in Dynamics NAV tenendo presente il fatto che non c’è corrispondenza tra la lunghezza delle stringhe Unicode e quelle Dynamics NAV equivalenti.
Il test del corretto funzionamento delle funzioni può essere fatto tramite le seguenti chiamate:
Code\Encode Functions
Encoding nav = Encoding.GetEncoding(1252);
Encoding unicode = Encoding.GetEncoding(932);
byte[] unicodeBytes = unicode.GetBytes(textBox1.Text);
textBox2.Text = nav.GetString(unicodeBytes);
Select with Functions
select dbo.NAV2Chinese(N'²ÊƼ Îâ')
example
Riferimenti:
Microsoft Officials
http://blogs.msdn.com/b/nav/archive/2009/06/16/how-to-manage-nav-dbcs-data-using-c.aspx
https://mbs2.microsoft.com/Knowledgebase/KBDisplay.aspx?scid=kb$EN-US$915374&wa=wsignin1.0
http://blogs.msdn.com/b/freddyk/archive/2008/11/04/transferring-data-to-from-com-automation-bjects-and-webservices.aspx
Encoding code page (ex: 1252 ITA)
http://msdn.microsoft.com/en-us/library/system.text.encoding_members.aspx
Blog Kekunda
http://petrescent5.kekunda.com/chan-4194086/all_p1.html
Referencing a custom assembly inside a Script Task
http://microsoft-ssis.blogspot.it/2011/05/referencing-custom-assembly-inside.html
http://microsoft-ssis.blogspot.it/
NAV 2013 SOAP Web Services on a multilanguage environment
http://blogs.msdn.com/b/nav/archive/2012/11/07/nav-2013-soap-web-services-on-a-multilanguage-environment.aspx
Pillole di programmazione C#, C++
http://www.aino.it/Attivita/Appunti_C_Sharp/Programmazione.htm
by Roberto Stefanetti