Localization & Multi-language Support

Source: source/function/strings.prg

FiveWin's localization system provides centralized multi-language support through FWString() and FWSetLanguage(). Hundreds of predefined translations are stored in a static array within strings.prg, covering English, Spanish, French, Portuguese, German, and Italian. All framework components -- windows, menus, dialogs, reports, print previews, and error handlers -- retrieve UI text through this unified system. Applications can switch languages at runtime or add new languages with custom translation tables.

Architecture

flowchart LR subgraph "Application Code" A[FWString
cEnglish] B[FWSetLanguage
nLang] end subgraph "Core Engine (strings.prg)" C[aStrings Array] D[nLanguage] end A --> C B --> D D --> A C -->|"aStrings[i][nLang]"| A A --> E[Localized UI]

Language Constants

IDLanguageArray Index
1English (EN)1
2Spanish (ES)2
3French (FR)3
4Portuguese (PT)4
5German (DE)5
6Italian (IT)6

Core Functions

FWString()

FWString( cEnglishText ) --> cLocalized

The primary interface for retrieving localized text. Searches the aStrings array for the English key and returns the translation for the currently selected language. Falls back to the original text if no translation is found.

? FWString( "Save" )     // "Guardar" (if language = Spanish)
? FWString( "Cancel" )    // "Annuler" (if language = French)

FWSetLanguage()

FWSetLanguage( nLang [, cLang ] ) --> nPrevLang

Sets the active language by its numeric ID (1-6). An optional string name ("ES", "FR", etc.) can be passed for readability. Returns the previous language ID. All subsequent FWString() calls use the new language.

FWSetLanguage( 2 )    // Switch to Spanish
FWSetLanguage( 4 )    // Switch to Portuguese

FWAddLanguage()

FWAddLanguage( cLang, hStrings ) --> lSuccess

Adds a new language with a custom translation hash. cLang is a two-letter code and hStrings is a hash mapping each English string to its translation. This allows includable translation modules without modifying strings.prg itself.

FWMissingStrings()

FWMissingStrings( lWriteToFile ) --> nCount

Reports the number of strings used by the application that have no translation for the current language. When lWriteToFile is .T., writes the missing strings to a text file for translator reference.

FWAddString()

FWAddString( cEnglish, cTranslated ) --> nil

Adds a single string pair to the current language's translation table at runtime. Useful for application-specific strings not in the predefined set.

FWSetString()

FWSetString( nLang, cEnglish, cTranslated ) --> nil

Sets or overrides the translation of an English key for a specific language. Allows patching individual entries without reloading the entire table.

FWLanguageID()

FWLanguageID() --> nLang

Returns the numeric ID of the currently active language (1-6). Useful for conditional logic that depends on the active language (e.g., handling leading punctuation in Spanish).

if FWLanguageID() == 2  // Spanish
   cPrompt := FWString( "Open" ) + " " + FWString( "file" )
endif

FWLoadStrings() / FWSaveStrings()

FWLoadStrings( cFile ) --> lSuccess
FWSaveStrings( cFile ) --> lSuccess

Load or save the complete translation table from/to a text file. Useful for shipping separate language packs or allowing end-user translation customization.

File Encoding

The strings.prg source file must be encoded as CP1252 (Western European), not UTF-8. Accented characters are stored as single bytes (e.g., n=0xF1, a=0xE4, u=0xFC). The Harbour compiler preserves string literal bytes as-is, so the encoding must match the expected codepage at compile time.

Unicode & Codepage Support

FiveWin supports Unicode applications through FW_SetUnicode(.T.), which must be called before any window is created. When Unicode mode is active:

Enabling Unicode

#include "FiveWin.ch"

function Main()
   FW_SetUnicode( .T. )  // Must be called before any UI
   // ... rest of app
return nil

Asian & Multi-byte Codepages

For non-Unicode applications requiring Asian languages, Harbour's codepage system must be configured at startup:

LanguageCodepagehb_cdpSelect()Notes
Chinese TraditionalBig5 (CP 950)"zh_TW" / "BIG5"Taiwan, Hong Kong
Chinese SimplifiedGB2312 / GBK (CP 936)"zh_CN" / "GBK"Mainland China
JapaneseShift-JIS (CP 932)"ja_JP" / "SJIS"Windows-31J
KoreanEUC-KR (CP 949)"ko_KR" / "EUCKR"Unified Hangul
RussianCP 1251"ru_RU" / "RU1251"Cyrillic
ArabicCP 1256"ar_SA" / "AR1256"Right-to-left
HebrewCP 1255"he_IL" / "HE1255"Right-to-left
GreekCP 1253"el_GR" / "GR1253"
TurkishCP 1254"tr_TR" / "TR1254"
ThaiCP 874"th_TH" / "TH874"
UTF-8CP 65001"UTF8"Recommended for new apps
// Set codepage at startup for Big5 (Traditional Chinese)
REQUEST HB_LANG_ZH_TW
hb_cdpSelect( "zh_TW" )
hb_LangSelect( "zh_TW" )

// Or for UTF-8
REQUEST HB_LANG_EN
hb_cdpSelect( "UTF8" )

FW_SetUnicode() Details

When FW_SetUnicode(.T.) is active:

Custom Language Tables (Beyond 6 Built-in)

The FWAddLanguage() function supports adding languages beyond the 6 built-in. The system supports up to Len(aStrings[1]) languages (currently 10 slots available). Use FWSetLanguage(n) with an ID > 6 after adding the language:

// Add Chinese (ID 7) translation table
FWAddLanguage( "ZH", { "Save" => "保存", "Cancel" => "取消", ;
   "File" => "文件", "Open" => "打开" } )
FWSetLanguage( 7 )

Example: Multi-language App

#include "FiveWin.ch"

function Main()

   local oWnd, oMenu

   DEFINE WINDOW oWnd TITLE "Localization Demo" ;
      MENU BuildMenu( oWnd ) ;
      SIZE 600, 400

   ACTIVATE WINDOW oWnd

return nil

function BuildMenu( oWnd )

   local oMenu

   MENU oMenu
      MENUITEM FWString( "&File" )
      MENU
         MENUITEM FWString( "&Open" ) ACTION MsgInfo( FWString( "Open file" ) )
         MENUITEM FWString( "E&xit" )  ACTION oWnd:End()
      ENDMENU
      MENUITEM "Language"
      MENU
         MENUITEM "English"   ACTION ( FWSetLanguage( 1 ), oWnd:SetMenu( BuildMenu( oWnd ) ) )
         MENUITEM "Espanol"   ACTION ( FWSetLanguage( 2 ), oWnd:SetMenu( BuildMenu( oWnd ) ) )
         MENUITEM "Francais"  ACTION ( FWSetLanguage( 3 ), oWnd:SetMenu( BuildMenu( oWnd ) ) )
         MENUITEM "Deutsch"   ACTION ( FWSetLanguage( 5 ), oWnd:SetMenu( BuildMenu( oWnd ) ) )
         MENUITEM "Italiano"  ACTION ( FWSetLanguage( 6 ), oWnd:SetMenu( BuildMenu( oWnd ) ) )
      ENDMENU
   ENDMENU

return oMenu