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
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
| ID | Language | Array Index |
|---|---|---|
| 1 | English (EN) | 1 |
| 2 | Spanish (ES) | 2 |
| 3 | French (FR) | 3 |
| 4 | Portuguese (PT) | 4 |
| 5 | German (DE) | 5 |
| 6 | Italian (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:
- All strings are UTF-8 encoded internally
- Windows controls receive UTF-16 via automatic conversion in
fwunicode.c hb_cdpSelect("UTF8")is used as the Harbour codepage- String literals in
.prgsource files must be saved as UTF-8
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:
| Language | Codepage | hb_cdpSelect() | Notes |
|---|---|---|---|
| Chinese Traditional | Big5 (CP 950) | "zh_TW" / "BIG5" | Taiwan, Hong Kong |
| Chinese Simplified | GB2312 / GBK (CP 936) | "zh_CN" / "GBK" | Mainland China |
| Japanese | Shift-JIS (CP 932) | "ja_JP" / "SJIS" | Windows-31J |
| Korean | EUC-KR (CP 949) | "ko_KR" / "EUCKR" | Unified Hangul |
| Russian | CP 1251 | "ru_RU" / "RU1251" | Cyrillic |
| Arabic | CP 1256 | "ar_SA" / "AR1256" | Right-to-left |
| Hebrew | CP 1255 | "he_IL" / "HE1255" | Right-to-left |
| Greek | CP 1253 | "el_GR" / "GR1253" | |
| Turkish | CP 1254 | "tr_TR" / "TR1254" | |
| Thai | CP 874 | "th_TH" / "TH874" | |
| UTF-8 | CP 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:
- fwunicode.c:
hbcdp_to_wincdp()converts OEM codepages (<1250) to CP_ACP whenbAnsiOnlyis TRUE, avoiding double-encoding of CP1252 text with CP437 - Dialog templates:
dlg2chr.candctrl2chr.cuse CP_ACP (not CP_OEMCP) for MultiByteToWideChar conversion - Common controls: apps with Windows XP manifest create Unicode common controls;
fwunicode.chandles the encoding bridge - GET/MultiGet:
lWideCharflag usesKeyWChar()for Unicode character input
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