Montando uma rotina multi idiomas


Outro dia, me pediram um relatório que permitisse imprimi-lo em vários idiomas (português,inglês,espanhol e alemão). Então fiquei pensando, qual seria a melhor escolha para desenvolver. multiidiomas Na dica abaixo, irei exemplificar como fazer tal código, seja para um relatório quanto para uma tela. Inicialmente montei a pergunta

Static Function CriaSX1(cPerg)
PutSx1(cPerg, "01","Idioma?", "", "", "mv_ch1", "N",1, 0, 1, "C", "", "", "", "", "mv_par01", ;
              "Português", "", "", "", ;
              "English"  , "", "", ;
              "Español"  , "", "", ;
              "Deutsch"  , "", "", "", "", "", {"Selecione o idioma","",""}, {"","",""}, {"","",""})
Return
Pensei em algumas opções, umas delas foi utilizando array
Private aTitulo := {"Titulo","Title","Titulo","Titel"} //Portugues, Ingles, Espanhol, Alemão
Então meu fonte ficaria assim:
#include "Protheus.ch"

User Function MeuFonte()
    //Declaro minhas variaveis
    Private aTitulo := {"Titulo","Title","Titulo","Titel"} //Portugues, Ingles, Espanhol, Alemão
    Private nIdioma := 0
    Private cTitulo := ""
    
    //Crio a pergunta caso não exista
    CriaSX1("MEUFONTE")
    //Exibo a pergunta
    Pergunte("MEUFONTE",.T.) 
    
    //Para ficar mais facil para entender, eu coloco na variavel nIdioma o retorno da pergunta
    nIdioma := mv_par01

    //Defino o conteudo das variaveis conforme o idioma seleciondo
    cTitulo  := aTitulo[nIdioma]

    ********   
    //Imprimo o texto conforme o idioma
    alert(cTitulo) ou alert(aTitulo[nIdioma])

Return

Static Function OutraTela()
    //como declarei a variavel como Private, posso chamá-la de qualquer outra função
    alert(cTitulo)
Return
Outra forma que pode ser usada é usando arquivo texto externo, tipo:
Arquivo: meufonte1.txt //Portugues
Arquivo: meufonte2.txt //Ingles
Arquivo: meufonte3.txt //Espanhol
Arquivo: meufonte4.txt //Alemão

ou

Arquivo: meufonte.portugues
Arquivo: meufonte.english
Arquivo: meufonte.espanol
Arquivo: meufonte.deutsch

O conteúdo dos arquivos
Português Inglês Espanhol Alemão
Laranja Orange Naranja Orange
Uva Grape Uva Traube
Maça Apple Manzana Apfel
O fonte pode ficar assim considerando a pergunta
Static Function CriaSX1(cPerg)
PutSx1(cPerg, "01","Idioma?", "", "", "mv_ch1", "N",1, 0, 0, "C", "", "", "", "", "mv_par01", ;
              "Português", "", "", "", ;
              "English"  , "", "", ;
              "Español"  , "", "", ;
              "Deutsch"  , "", "", "", "", "", {"Selecione o idioma","",""}, {"","",""}, {"","",""})
Return

Exemplo 1

#Include 'Protheus.ch'
User Function MeuFonte()
	Local nIdioma   := 0
	Local cArquivo  := ""
	Private aIdioma := {}
	
        CriaSX1("MEUFONTE")
	Pergunte("MEUFONTE",.T.) 
        nIdioma  := MV_PAR01

        cArquivo := "\system\idiomas\meufonte"+Alltrim(Str(nIdioma))+".txt"
	
	if Ler(cArquivo)
		For i:=1 to len(aIdioma)
			alert(aIdioma[i])
		Next
	endif
Return
ou assim:

Exemplo 2

Static Function CriaSX1(cPerg)
PutSx1(cPerg, "01","Idioma?", "", "", "mv_ch1", "N",1, 0, 0, "C", "", "", "", "", "mv_par01", ;
              "Portugues", "", "", "", ;
              "English"  , "", "", ;
              "Espanol"  , "", "", ;
              "Deutsch"  , "", "", "", "", "", {"Selecione o idioma","",""}, {"","",""}, {"","",""})
Return
#Include 'Protheus.ch'
User Function MeuFonte()
	Local cIdioma := ""
	Local cArquivo := ""
	Private aIdioma := {}
	
	CriaSX1("MEUFONTE")
	if !Pergunte("MEUFONTE",.T.)
		return
	endif

	cIdioma := SelIdi(mv_par01,"MEUFONTE") //pega o texto do combo ao invés da posição

	cArquivo := "\system\idiomas\meufonte."+lower(cIdioma)

	if Ler(cArquivo)
		For i:=1 to len(aIdioma)
			alert(aIdioma[i])
		Next
	endif
Return
Criei a função SelIdi(), apenas para capturar o texto da seleção, pode fazer de outras maneiras, mas vou postar abaixo uma delas:
Static Function SelIdi(nOpc,cPerg)
	Local cRet   := ""
	
	Pergunte(cPerg,.F.)	
	dbSelectArea("SX1")
	dbSetOrder(1)
	dbSeek(cPerg)
	While !Eof() .And. AllTrim(SX1->X1_GRUPO) == cPerg .and. SX1->X1_ORDEM == "01" //como sei que a ordem é a primeira, já deixei chumbado
		cCampo := @("SX1->X1_DEF"+StrZero(nOpc,2)) //pego a posição e concateno com o resto do nome do campo
		cRet := &cCampo		//pego apenas o conteudo usando a macro substituição
		dbSelectArea("SX1")
		dbSkip()
	EndDo
Return(cRet)
O fonte abaixo é para ler um arquivo texto
Static Function Ler(cArquivo)
	Local cLinha := ""
	Local nHdl 
	Local lRet   := .F.

	nHdl := fOpen(cArquivo)

	If nHdl == -1 
		IF FERROR()== 516 
		    ALERT("Feche a planilha que gerou o arquivo.")
		EndIF
	EndIf
	
	//+---------------------------------------------------------------------+
	//| Verifica se foi possível abrir o arquivo                            |
	//+---------------------------------------------------------------------+
	If nHdl == -1
		MsgAlert("O arquivo de nome "+Alltrim(cArquivo)+" nao pode ser aberto! Verifique os parametros.","Atencao!")
	   	Return
	Endif
	
	FSEEK(nHdl,0,0) //Posiciona no inicio do arquivo
		
	fClose(nHdl)       //fecha o arquivo
	FT_FUse(cArquivo)  //abre o arquivo 
	FT_FGOTOP()         //posiciona na primeira linha do arquivo      
	
	aIdioma:={}	      
	While !FT_FEOF()	   		  
		clinha := FT_FREADLN()			
		if !empty(cLinha)
			AADD(aIdioma,cLinha)
		endif			

		FT_FSKIP()
	EndDo

	FT_FUse()
	fClose(nHdl)
	
	if Len(aIdioma)>0
		lRet := .T.
	Endif
Return(lRet)
Espero que tenha sido útil, dúvidas? Comente...