Creating language files and integrating with MUI: Difference between revisions

From NSIS Wiki
Jump to navigationJump to search
mNo edit summary
 
(3 intermediate revisions by 2 users not shown)
Line 3: Line 3:
== Introduction ==
== Introduction ==
Taken from a forum posting by [[user:rainwater | rainwater]] in response to the following question by [[sealite | sealite]]:----I have some experience in creating multilanguage applications. The best solution, from my
Taken from a forum posting by [[user:rainwater | rainwater]] in response to the following question by [[sealite | sealite]]:----I have some experience in creating multilanguage applications. The best solution, from my
experience, is to create language files but it seams that NSIS does not have support for this.
experience, is to create language files but it seems that NSIS does not have support for this.
(I'm not reffering to standard language files).
(I'm not referring to standard language files).


== Issue ==
== Issue ==
Line 40: Line 40:
Then make your language files like:
Then make your language files like:


<highlight-nsis>!define LANG "ENGLISH" ; Must be the lang name define my NSIS
<highlight-nsis>!define LANG "ENGLISH" ; Must be the lang name define by NSIS
!insertmacro LANG_STRING STRING_BRANDING "My Setup"
!insertmacro LANG_STRING STRING_BRANDING "My Setup"
!insertmacro LANG_STRING STRING_APP_OLD "This application is old."</highlight-nsis>
!insertmacro LANG_STRING STRING_APP_OLD "This application is old."</highlight-nsis>
Line 89: Line 89:
And your installer is ready to be compiled with makensis.
And your installer is ready to be compiled with makensis.
</pre>
</pre>
== Another solution: Native PO File support ==
After being frustrated with the tools required to get the above two methods functioning, I decided to take a completely new approach. This method only relies on a toolchain only if you want to compile a multi-language installer - so the raw NSI is always compilable.  It eliminates many intermediate stages of previous approaches and makes it much easier for both the developers and translators to get on with doing more important stuff.
This method attempts to integrate "native" gettext functionality into NSIS, facilitated by a series of Python scripts.  build_gettext_catalog_nsi.py scans for LangString's and compiles them into a .pot file.  Then, build_locale_nsi.py creates a new NSIS with localized LangStrings from PO files, which can be built.
If you don't know already, PO files are more or less the most popular way to translate software, and are best supported for developers and translators.  Hence, I think this method trumps previous solutions.
=== Requirements ===
* [http://code.google.com/p/unsis/ NSIS Unicode build]
* [http://python.org Python 2.7+]
* [https://pypi.python.org/pypi/polib Polib] - Library for python to manipulate PO files
* Build script [http://mtasa-blue.googlecode.com/svn/branches/L10n/utils/build_gettext_catalog_nsi.py build_gettext_catalog_nsi.py] and [http://mtasa-blue.googlecode.com/svn/branches/L10n/utils/build_locale_nsi.py build_locale_nsi.py]
=== Prepare your NSIS ===
How does it work?  First, you need to add a the default language plus a commented line to your file (rather than raw string - prevents syntax errors when not using the toolchain).  This should come '''after''' you define MUI pages, but '''before''' you use any language strings:
<highlight-nsis>
!insertmacro MUI_LANGUAGE "English"
;@INSERT_TRANSLATIONS@
</highlight-nsis>
Assuming "English" is your default language.  If not, change it.
Then you need to prepare your .nsi file appropriately, by using your typical LangStrings - for example:
<highlight-nsis>
LangString HEADER_Text ${LANG_English} "Grand Theft Auto: San Andreas location"
LangString DIRECTORY_Text_Dest ${LANG_English} "Grand Theft Auto: San Andreas folder"
LangString DIRECTORY_Text_Top ${LANG_English} "Please select your Grand Theft Auto: San Andreas folder."
!define MUI_PAGE_HEADER_TEXT "$(HEADER_Text)"
!define MUI_DIRECTORYPAGE_TEXT_DESTINATION "$(DIRECTORY_Text_Dest)"
!define MUI_DIRECTORYPAGE_TEXT_TOP "$(DIRECTORY_Text_Top)"
</highlight-nsis>
=== Build your .pot file ===
For this, you use build_gettext_catalog_nsi.py, which offers the following parameters:
* "-i", "--input" '''Source .nsi location'''
* "-o", "--output" '''POT file output location'''
* "-p", "--project" '''Project name to write to the POT file'''
* "-v", "--version" '''Version to write to the POT file'''
* "-l", "--lang" '''Default language of the NSI'''
So for example:
<pre>
build_gettext_catalog_nsi.py -i project.nsi -o messages.pot -p "My Project" -v "1.0" -l "English"
</pre>
The script will then scan the project.nsi for LangString's of the default language (-l param), and compile a .pot file from it.  This can then be accessed in any PO editor, such as POEdit, then new translations are saved as .po files.
If you need to add more metadata, you can always modify the build_gettext_catalog_nsi.py itself. 
=== Merge your translated .po files ===
Once your minions have translated your files, you merge them back into the .nsi.  This stage requires build_locale_nsi.py, which offers the following parameters:
* "-i", "--input" '''Source .nsi location (same as before)'''
* "-o", "--output" '''Localized .nsi output location'''
* "-p", "--podir" '''Directory containing PO files (should be named according to locale, i.e. fr.po, de.po, pt.po etc)'''
* "-l", "--lang" '''Default language of the NSI (same as before)'''
So for example:
<pre>
build_locale_nsi.py -i project.nsi -o project_multilang.nsi -p "locale/pofiles/" -l "English"
</pre>
Where -p is a directory containing PO files (also scans subdirectories)
The script will then scan the specified directory for PO files, read them, and insert a series of MUI_LANGUAGE macros and LangString's of other languages, at the position you specified using ;@INSERT_TRANSLATIONS, and save it to the seperate output file.
This new .nsi is now ready to compile, and should enable multilanguage support.  Remember, there are a few other parameters you have to ensure are enabled for multilanguage NSIs to work, see the [http://nsis.sourceforge.net/Examples/Modern%20UI/MultiLanguage.nsi MUI Multilanguage example]


[[Category:Tutorials]]
[[Category:Tutorials]]

Latest revision as of 15:23, 28 May 2013

Author: sunjammer (talk, contrib)


Introduction

Taken from a forum posting by rainwater in response to the following question by sealite:----I have some experience in creating multilanguage applications. The best solution, from my experience, is to create language files but it seems that NSIS does not have support for this. (I'm not referring to standard language files).

Issue

As you know, you'll need at some time to display a message like "This application is old" but the NSIS can't do the translation in other languages so someone else will do the translation for him. But the translator is not a programmer! So the only solution is to include in the script only macros like LANG_MSG_APP_OLD and create language files like:

English.lng LANG_MSG_APP_OLD "This application is old."

Does anyone know how can we do this?

Solution

Rainwater suggested the following solution:

First create these macros in your installer:

!macro LANG_LOAD LANGLOAD
  !insertmacro MUI_LANGUAGE "${LANGLOAD}"
  !verbose off
  !include "locallang\${LANGLOAD}.nsh"
  !verbose on
  BrandingText "$(STRING_BRANDING)" ; example usage
  !undef LANG
!macroend
 
!macro LANG_STRING NAME VALUE
  LangString "${NAME}" "${LANG_${LANG}}" "${VALUE}"
!macroend
 
!macro LANG_UNSTRING NAME VALUE
  !insertmacro LANG_STRING "un.${NAME}" "${VALUE}"
!macroend

Then make your language files like:

!define LANG "ENGLISH" ; Must be the lang name define by NSIS
!insertmacro LANG_STRING STRING_BRANDING "My Setup"
!insertmacro LANG_STRING STRING_APP_OLD "This application is old."

If you create language files (ie "English.nsh") in the directory ("locallang" in this example), then in the head of your installer, you just say:

!insertmacro LANG_LOAD "English"

and it will load the MUI, NSIS, and your local language files.

Solution improved

Here is a perl tool that is based on the above solution but goes further to make the translations available in regular po files.

It is very easy to integrate it in the GNU toolchain. It uses a .desktop file as a holder for the translations. The intltool-merge tool knows how to insert translations from a po file to a .desktop file. If you don't use the intltools, you can also easily create and maintain the pseudo desktop file manually.

InstallerIsRunning=The installer is already running.
InstallerIsRunning[fr]=Le programme d'installation est déjà en cours d'exécution.
GcomprisLicenseButton=Next >
GcomprisLicenseButton[fr]=Suivant >

Once you have prepared you pseudo .desktop file, you have to add the line @INSERT_TRANSLATIONS@ in your nsis source file. Put it before you starting using your translations.

Last step is to run the script create_nsis_translations.pl. It will create all the translations file for you and update your nsis source file.

As a summary, with this tool adding a new string is done by adding a line in the pseudo .desktop file. Then the translations are done through the regular .po files.

Here is an overview of the translation process:

nsis.desktop.in  -> intltool-extract -> .po files
.po files are translated by the translation team of your project.
nsis.desktop.in + .po files -> intltool-merge -> nsis.desktop

Add the line @INSERT_TRANSLATIONS@ to you project.nsis source installer file.
Use the translations string in you source installer file.

Now you can run:
./create_nsis_translations.pl nsis.desktop project.nsis tmp_directory
And your installer is ready to be compiled with makensis.

Another solution: Native PO File support

After being frustrated with the tools required to get the above two methods functioning, I decided to take a completely new approach. This method only relies on a toolchain only if you want to compile a multi-language installer - so the raw NSI is always compilable. It eliminates many intermediate stages of previous approaches and makes it much easier for both the developers and translators to get on with doing more important stuff.

This method attempts to integrate "native" gettext functionality into NSIS, facilitated by a series of Python scripts. build_gettext_catalog_nsi.py scans for LangString's and compiles them into a .pot file. Then, build_locale_nsi.py creates a new NSIS with localized LangStrings from PO files, which can be built.

If you don't know already, PO files are more or less the most popular way to translate software, and are best supported for developers and translators. Hence, I think this method trumps previous solutions.

Requirements

Prepare your NSIS

How does it work? First, you need to add a the default language plus a commented line to your file (rather than raw string - prevents syntax errors when not using the toolchain). This should come after you define MUI pages, but before you use any language strings:

!insertmacro MUI_LANGUAGE "English"
;@INSERT_TRANSLATIONS@

Assuming "English" is your default language. If not, change it.

Then you need to prepare your .nsi file appropriately, by using your typical LangStrings - for example:

LangString 	HEADER_Text		${LANG_English}	"Grand Theft Auto: San Andreas location"
LangString 	DIRECTORY_Text_Dest	${LANG_English}	"Grand Theft Auto: San Andreas folder"
LangString 	DIRECTORY_Text_Top	${LANG_English}	"Please select your Grand Theft Auto: San Andreas folder."
 
!define MUI_PAGE_HEADER_TEXT				"$(HEADER_Text)"
!define MUI_DIRECTORYPAGE_TEXT_DESTINATION		"$(DIRECTORY_Text_Dest)"
!define MUI_DIRECTORYPAGE_TEXT_TOP			"$(DIRECTORY_Text_Top)"

Build your .pot file

For this, you use build_gettext_catalog_nsi.py, which offers the following parameters:

  • "-i", "--input" Source .nsi location
  • "-o", "--output" POT file output location
  • "-p", "--project" Project name to write to the POT file
  • "-v", "--version" Version to write to the POT file
  • "-l", "--lang" Default language of the NSI

So for example:

build_gettext_catalog_nsi.py -i project.nsi -o messages.pot -p "My Project" -v "1.0" -l "English"

The script will then scan the project.nsi for LangString's of the default language (-l param), and compile a .pot file from it. This can then be accessed in any PO editor, such as POEdit, then new translations are saved as .po files.

If you need to add more metadata, you can always modify the build_gettext_catalog_nsi.py itself.

Merge your translated .po files

Once your minions have translated your files, you merge them back into the .nsi. This stage requires build_locale_nsi.py, which offers the following parameters:

  • "-i", "--input" Source .nsi location (same as before)
  • "-o", "--output" Localized .nsi output location
  • "-p", "--podir" Directory containing PO files (should be named according to locale, i.e. fr.po, de.po, pt.po etc)
  • "-l", "--lang" Default language of the NSI (same as before)

So for example:

build_locale_nsi.py -i project.nsi -o project_multilang.nsi -p "locale/pofiles/" -l "English"

Where -p is a directory containing PO files (also scans subdirectories)

The script will then scan the specified directory for PO files, read them, and insert a series of MUI_LANGUAGE macros and LangString's of other languages, at the position you specified using ;@INSERT_TRANSLATIONS, and save it to the seperate output file.

This new .nsi is now ready to compile, and should enable multilanguage support. Remember, there are a few other parameters you have to ensure are enabled for multilanguage NSIs to work, see the MUI Multilanguage example