Created
January 22, 2012 21:26
-
-
Save AzureKitsune/1658899 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# | |
# Nimrod's Runtime Library | |
# (c) Copyright 2011 Alex Mitchell | |
# | |
# See the file "copying.txt", included in this | |
# distribution, for details about the copyright. | |
# | |
## :Author: Alex Mitchell | |
## | |
## This module implements a way of pulling localized strings from an .ini file. | |
import parsecfg, tables, streams, strutils | |
type | |
TLanguage = object of TObject | |
Region*: string | |
Dialect*: string | |
DisplayName*: string | |
TLocaleData = object of TObject | |
ID: string | |
Name: string | |
Keys: TTable[string,string] | |
TLocaleManager = object of TObject | |
Data: seq[TLocaleData] | |
DefaultLanguage*: TLanguage | |
proc getLocaleName(): string | |
proc `$`*(s: TLanguage): string = | |
result = s.DisplayName | |
proc parseLanguageCode*(code: string): TLanguage = | |
var bits = split(code, '-') | |
result.Region = bits[0] | |
result.Dialect = bits[1] | |
# Add other regions to this. | |
when defined(windows): | |
proc ResolveLocaleName(lpNameToResolve: WideCString, lpLocaleName: WideCString, cchLocaleName: cint): cint {.stdcall, dynlib: "kernel32", importc: "ResolveLocaleName".} | |
var buf: array[0..50, TUtf16Char] | |
discard ResolveLocaleName(toWideCString(result.Region), cast[WideCString](addr(buf)), 85) | |
result.DisplayName = $cast[WideCString](addr(buf)) | |
proc getLanguage*(): TLanguage = | |
result = parseLanguageCode(getLocaleName()) | |
proc initLocaleManager*(): TLocaleManager = | |
result.Data = @[] | |
result.DefaultLanguage = getLanguage() | |
proc loadLocaleFile*(localeM: var TLocaleManager, file: string) = | |
var fileStr = newFileStream(file,fmRead) | |
var cfg : TCfgParser | |
open(cfg, fileStr, file) | |
var loc: TLocaleData | |
while true: | |
var e = next(cfg) | |
case e.kind | |
of cfgEof: | |
localeM.Data.add(loc) # add the last locale | |
break | |
of cfgSectionStart: | |
if loc.Name != nil: | |
localeM.Data.add(loc) | |
loc.Name = e.section | |
loc.Keys = initTable[string,string]() | |
of cfgKeyValuePair: | |
loc.Keys.add(e.key,e.value) | |
else: nil | |
close(cfg) | |
proc getLocalizedString*(loc: TLocaleManager, key: string, langname: string): string = | |
for lang in loc.Data: | |
if lang.Name == langname: | |
result = lang.Keys[key] | |
break | |
proc getLocalizedString*(loc: TLocaleManager, key: string): string = | |
result = getLocalizedString(loc, key, loc.DefaultLanguage.DisplayName) | |
when defined(windows): | |
from windows import LCID | |
# function below only works on Vista and up. | |
proc GetUserDefaultLocaleName*(lpLocaleName: WideCString, cchLocaleName: cint): cint {.stdcall, dynlib: "kernel32", importc: "GetUserDefaultLocaleName".} | |
proc GetUserDefaultLCID*(): LCID {.stdcall, dynlib: "kernel32", importc: "GetUserDefaultLCID".} | |
proc getLocaleName(): string = | |
#var name: array[0..86, TUtf16Char] | |
#var len = GetUserDefaultLocaleName(cast[WideCString](addr(name)), 85) - 1 | |
#echo(len) | |
#echo(len(cast[WideCString](addr(name)))) | |
#result = $cast[WideCString](addr(name)) | |
var l = GetUserDefaultLCID() | |
# <araq_bnc> (x shr 16) and 0B1111 == sort_id | |
# <araq_bnc> x and 0xffff == language_id | |
result = "en-US" | |
when isMainModule: | |
var localeM = initLocaleManager() | |
echo(localeM.DefaultLanguage.DisplayName) | |
localeM.loadLocaleFile("myLocale.ini") | |
echo(localeM.getLocalizedString("welcome")) | |
echo(localeM.getLocalizedString("welcome", "Spanish")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[English] | |
welcome="Welcome to my localized Nimrod program." | |
[Spanish] | |
welcome="Bienvenidos a mi localizada programa Nimrod." |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
type | |
TUtf16Char = distinct int16 | |
WideCString = ptr array[0.. 1_000_000, TUtf16Char] | |
const | |
utf8Encoding = 65001 | |
proc len(w: WideCString): int = | |
while int16(w[result]) != 0'i16: inc result | |
proc MultiByteToWideChar( | |
CodePage: int32, | |
dwFlags: int32, | |
lpMultiByteStr: cstring, | |
cbMultiByte: cint, | |
lpWideCharStr: WideCString, | |
cchWideChar: cint): cint {. | |
stdcall, importc: "MultiByteToWideChar", dynlib: "kernel32".} | |
proc WideCharToMultiByte( | |
CodePage: int32, | |
dwFlags: int32, | |
lpWideCharStr: WideCString, | |
cchWideChar: cint, | |
lpMultiByteStr: cstring, | |
cbMultiByte: cint, | |
lpDefaultChar: cstring=nil, | |
lpUsedDefaultChar: pointer=nil): cint {. | |
stdcall, importc: "WideCharToMultiByte", dynlib: "kernel32".} | |
proc `$`*(s: WideCString, len: int): string = | |
# special case: empty string: needed because MultiByteToWideChar | |
# return 0 in case of error: | |
if len == 0: return "" | |
# educated guess of capacity: | |
var cap = len + len shr 2 | |
result = newStringOfCap(cap) | |
let m = WideCharToMultiByte( | |
CodePage = utf8Encoding, | |
dwFlags = 0'i32, | |
lpWideCharStr = s, | |
cchWideChar = cint(len), | |
lpMultiByteStr = cstring(result), | |
cbMultiByte = cap) | |
if m == 0: | |
# try again; ask for capacity: | |
cap = WideCharToMultiByte( | |
CodePage = utf8Encoding, | |
dwFlags = 0'i32, | |
lpWideCharStr = s, | |
cchWideChar = cint(len), | |
lpMultiByteStr = nil, | |
cbMultiByte = cint(0)) | |
# and do the conversion properly: | |
result = newStringOfCap(cap) | |
let m = WideCharToMultiByte( | |
CodePage = utf8Encoding, | |
dwFlags = 0'i32, | |
lpWideCharStr = s, | |
cchWideChar = cint(len), | |
lpMultiByteStr = cstring(result), | |
cbMultiByte = cap) | |
if m == 0: OSError() | |
setLen(result, m) | |
elif m <= cap: | |
setLen(result, m) | |
else: | |
assert(false) # cannot happen | |
proc `$`*(s: WideCString): string = | |
result = s $ s.len | |
proc toWideCString*(s: string): WideCString = | |
## free after usage with `dealloc`. | |
let cap = s.len+1 | |
result = cast[wideCString](alloc0(cap * 2)) | |
# special case: empty string: needed because MultiByteToWideChar | |
# return 0 in case of error: | |
if s.len == 0: return | |
# convert to utf-16 LE | |
let m = MultiByteToWideChar(CodePage = utf8Encoding, dwFlags = 0'i32, | |
lpMultiByteStr = cstring(s), | |
cbMultiByte = cint(s.len), | |
lpWideCharStr = result, | |
cchWideChar = cint(cap)) | |
if m == 0: OSError() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment