improve documentation

This commit is contained in:
Vadim Lopatin 2014-12-16 17:01:22 +03:00
parent 62a5d27aca
commit 9e69b64f1b
3 changed files with 234 additions and 125 deletions

View File

@ -1,14 +1,32 @@
// Written in the D programming language. // Written in the D programming language.
/** /**
This module contains internationalization support implementation. This module contains UI internationalization support implementation.
Translation files contain of simple key=value pair lines. UIString struct provides string container which can be either plain unicode string or id of string resource.
STRING_RESOURCE_ID=Translation text. Translation strings are being stored in translation files, consisting of simple key=value pair lines:
---
STRING_RESOURCE_ID=Translation text 1
ANOTHER_STRING_RESOURCE_ID=Translation text 2
---
Supports fallback to another translation file (e.g. default language). Supports fallback to another translation file (e.g. default language).
If string resource is not found neither in main nor fallback translation files, UNTRANSLATED: RESOURCE_ID will be returned.
String resources must be placed in i18n subdirectory inside one or more resource directories (set using Platform.instance.resourceDirs
property on application initialization).
File names must be language code with extension .ini (e.g. en.ini, fr.ini, es.ini)
If several files for the same language are found in (different directories) their content will be merged. It's useful to merge string resources
from DLangUI framework with resources of application.
Set interface language using Platform.instance.uiLanguage in UIAppMain during initialization of application settings:
---
Platform.instance.uiLanguage = "en";
---
Synopsis: Synopsis:
@ -44,7 +62,12 @@ private import dlangui.core.linestream;
private import std.utf; private import std.utf;
private import std.algorithm; private import std.algorithm;
/** container for UI string - either raw value or string resource ID */ /**
Container for UI string - either raw value or string resource ID
Set resource id (string) or plain unicode text (dstring) to it, and get dstring.
*/
struct UIString { struct UIString {
/** if not null, use it, otherwise lookup by id */ /** if not null, use it, otherwise lookup by id */
private dstring _value; private dstring _value;
@ -61,13 +84,14 @@ struct UIString {
} }
/// Returns string resource id
@property string id() const { return _id; } @property string id() const { return _id; }
/// Sets string resource id
@property void id(string ID) { @property void id(string ID) {
_id = ID; _id = ID;
_value = null; _value = null;
} }
/** get value (either raw or translated by id) */ /** Get value (either raw or translated by id) */
@property dstring value() const { @property dstring value() const {
if (_value !is null) if (_value !is null)
return _value; return _value;
@ -76,55 +100,59 @@ struct UIString {
// translate ID to dstring // translate ID to dstring
return i18n.get(_id); return i18n.get(_id);
} }
/** set raw value */ /** Set raw value using property */
@property void value(dstring newValue) { @property void value(dstring newValue) {
_value = newValue; _value = newValue;
} }
/** assign raw value */ /** Assign raw value */
ref UIString opAssign(dstring rawValue) { ref UIString opAssign(dstring rawValue) {
_value = rawValue; _value = rawValue;
_id = null; _id = null;
return this; return this;
} }
/** assign ID */ /** Assign string resource id */
ref UIString opAssign(string ID) { ref UIString opAssign(string ID) {
_id = ID; _id = ID;
_value = null; _value = null;
return this; return this;
} }
/** default conversion to dstring */ /** Default conversion to dstring */
alias value this; alias value this;
} }
/** UIString item collection. */ /**
UIString item collection
Based on array.
*/
struct UIStringCollection { struct UIStringCollection {
private UIString[] _items; private UIString[] _items;
private int _length; private int _length;
/** returns number of items */ /** Returns number of items */
@property int length() { return _length; } @property int length() { return _length; }
/** slice */ /** Slice */
UIString[] opIndex() { UIString[] opIndex() {
return _items[0 .. _length]; return _items[0 .. _length];
} }
/** slice */ /** Slice */
UIString[] opSlice() { UIString[] opSlice() {
return _items[0 .. _length]; return _items[0 .. _length];
} }
/** slice */ /** Slice */
UIString[] opSlice(size_t start, size_t end) { UIString[] opSlice(size_t start, size_t end) {
return _items[start .. end]; return _items[start .. end];
} }
/** read item by index */ /** Read item by index */
UIString opIndex(size_t index) { UIString opIndex(size_t index) {
return _items[index]; return _items[index];
} }
/** modify item by index */ /** Modify item by index */
UIString opIndexAssign(UIString value, size_t index) { UIString opIndexAssign(UIString value, size_t index) {
_items[index] = value; _items[index] = value;
return _items[index]; return _items[index];
} }
/** return unicode string for item by index */ /** Return unicode string for item by index */
dstring get(size_t index) { dstring get(size_t index) {
return _items[index].value; return _items[index].value;
} }
@ -161,7 +189,7 @@ struct UIStringCollection {
add(item); add(item);
} }
} }
/** remove all items */ /** Remove all items */
void clear() { void clear() {
_items.length = 0; _items.length = 0;
_length = 0; _length = 0;
@ -226,14 +254,14 @@ struct UIStringCollection {
} }
} }
/** UI Strings internationalization translator. */ /** UI Strings internationalization translator */
synchronized class UIStringTranslator { synchronized class UIStringTranslator {
private UIStringList _main; private UIStringList _main;
private UIStringList _fallback; private UIStringList _fallback;
private string[] _resourceDirs; private string[] _resourceDirs;
/** looks for i18n directory inside one of passed dirs, and uses first found as directory to read i18n files from */ /** Looks for i18n directory inside one of passed dirs, and uses first found as directory to read i18n files from */
void findTranslationsDir(string[] dirs ...) { void findTranslationsDir(string[] dirs ...) {
_resourceDirs.length = 0; _resourceDirs.length = 0;
import std.file; import std.file;
@ -246,7 +274,7 @@ synchronized class UIStringTranslator {
} }
} }
/** convert resource path - append resource dir if necessary */ /** Convert resource path - append resource dir if necessary */
string[] convertResourcePaths(string filename) { string[] convertResourcePaths(string filename) {
if (filename is null) if (filename is null)
return null; return null;
@ -264,12 +292,13 @@ synchronized class UIStringTranslator {
return res; return res;
} }
/// create empty translator
this() { this() {
_main = new shared UIStringList(); _main = new shared UIStringList();
_fallback = new shared UIStringList(); _fallback = new shared UIStringList();
} }
/** load translation file(s) */ /** Load translation file(s) */
bool load(string mainFilename, string fallbackFilename = null) { bool load(string mainFilename, string fallbackFilename = null) {
_main.clear(); _main.clear();
_fallback.clear(); _fallback.clear();
@ -280,7 +309,7 @@ synchronized class UIStringTranslator {
return res; return res;
} }
/** translate string ID to string (returns "UNTRANSLATED: id" for missing values) */ /** Translate string ID to string (returns "UNTRANSLATED: id" for missing values) */
dstring get(string id) { dstring get(string id) {
if (id is null) if (id is null)
return null; return null;
@ -365,7 +394,7 @@ private shared class UIStringList {
} }
} }
/** Global translator object. */ /** Global UI translator object */
shared UIStringTranslator i18n; shared UIStringTranslator i18n;
shared static this() { shared static this() {
i18n = new shared UIStringTranslator(); i18n = new shared UIStringTranslator();

View File

@ -1,7 +1,10 @@
// Written in the D programming language. // Written in the D programming language.
/** /**
This module contains text file reader implementation.
This module contains text stream reader implementation
Implements class LineStream for reading of unicode text from stream and returning it by lines.
Support utf8, utf16, utf32 be and le encodings, and line endings - according to D language source file specification. Support utf8, utf16, utf32 be and le encodings, and line endings - according to D language source file specification.
@ -51,44 +54,74 @@ import std.stream;
import std.stdio; import std.stdio;
import std.conv; import std.conv;
/**
Support reading of file (or string in memory) by lines
Support utf8, utf16, utf32 be and le encodings, and line endings - according to D language source file specification.
Low resource consuming. Doesn't flood with GC allocations. Dup line if you want to store it somewhere.
Tracks line number.
*/
class LineStream { class LineStream {
/// File encoding
public enum EncodingType { public enum EncodingType {
/// plaing ASCII (character codes must be <= 127)
ASCII, ASCII,
/// utf-8 unicode
UTF8, UTF8,
/// utf-16 unicode big endian
UTF16BE, UTF16BE,
/// utf-16 unicode little endian
UTF16LE, UTF16LE,
/// utf-32 unicode big endian
UTF32BE, UTF32BE,
/// utf-32 unicode little endian
UTF32LE UTF32LE
}; };
InputStream _stream; /// Error codes
string _filename; public enum ErrorCodes {
ubyte[] _buf; // stream reading buffer /// invalid character for current encoding
uint _pos; // reading position of stream buffer INVALID_CHARACTER
uint _len; // number of bytes in stream buffer };
bool _streamEof; // true if input stream is in EOF state
uint _line; // current line number
uint _textPos; // start of text line in text buffer private InputStream _stream;
uint _textLen; // position of last filled char in text buffer + 1 private string _filename;
dchar[] _textBuf; // text buffer private ubyte[] _buf; // stream reading buffer
bool _eof; // end of file, no more lines private uint _pos; // reading position of stream buffer
private uint _len; // number of bytes in stream buffer
private bool _streamEof; // true if input stream is in EOF state
private uint _line; // current line number
private uint _textPos; // start of text line in text buffer
private uint _textLen; // position of last filled char in text buffer + 1
private dchar[] _textBuf; // text buffer
private bool _eof; // end of file, no more lines
/// Returns file name
@property string filename() { return _filename; } @property string filename() { return _filename; }
/// Returns current line number
@property uint line() { return _line; } @property uint line() { return _line; }
/// Returns file encoding EncodingType
@property EncodingType encoding() { return _encoding; } @property EncodingType encoding() { return _encoding; }
/// Returns error code
@property int errorCode() { return _errorCode; } @property int errorCode() { return _errorCode; }
/// Returns error message
@property string errorMessage() { return _errorMessage; } @property string errorMessage() { return _errorMessage; }
/// Returns line where error is found
@property int errorLine() { return _errorLine; } @property int errorLine() { return _errorLine; }
/// Returns line position (number of character in line) where error is found
@property int errorPos() { return _errorPos; } @property int errorPos() { return _errorPos; }
immutable EncodingType _encoding; private immutable EncodingType _encoding;
int _errorCode; private int _errorCode;
string _errorMessage; private string _errorMessage;
uint _errorLine; private uint _errorLine;
uint _errorPos; private uint _errorPos;
/// Open file with known encoding
protected this(InputStream stream, string filename, EncodingType encoding, ubyte[] buf, uint offset, uint len) { protected this(InputStream stream, string filename, EncodingType encoding, ubyte[] buf, uint offset, uint len) {
_filename = filename; _filename = filename;
_stream = stream; _stream = stream;
@ -99,8 +132,8 @@ class LineStream {
_streamEof = _stream.eof; _streamEof = _stream.eof;
} }
// returns slice of bytes available in buffer /// returns slice of bytes available in buffer
uint readBytes() { protected uint readBytes() {
uint bytesLeft = _len - _pos; uint bytesLeft = _len - _pos;
if (_streamEof || bytesLeft > QUARTER_BYTE_BUFFER_SIZE) if (_streamEof || bytesLeft > QUARTER_BYTE_BUFFER_SIZE)
return bytesLeft; return bytesLeft;
@ -117,12 +150,12 @@ class LineStream {
} }
// when bytes consumed from byte buffer, call this method to update position // when bytes consumed from byte buffer, call this method to update position
void consumedBytes(uint count) { protected void consumedBytes(uint count) {
_pos += count; _pos += count;
} }
// reserve text buffer for specified number of characters, and return pointer to first free character in buffer // reserve text buffer for specified number of characters, and return pointer to first free character in buffer
dchar * reserveTextBuf(uint len) { protected dchar * reserveTextBuf(uint len) {
// create new text buffer if necessary // create new text buffer if necessary
if (_textBuf == null) { if (_textBuf == null) {
if (len < TEXT_BUFFER_SIZE) if (len < TEXT_BUFFER_SIZE)
@ -153,12 +186,12 @@ class LineStream {
return _textBuf.ptr + _textLen; return _textBuf.ptr + _textLen;
} }
void appendedText(uint len) { protected void appendedText(uint len) {
//writeln("appended ", len, " chars of text"); //:", _textBuf[_textLen .. _textLen + len]); //writeln("appended ", len, " chars of text"); //:", _textBuf[_textLen .. _textLen + len]);
_textLen += len; _textLen += len;
} }
void setError(int code, string message, uint errorLine, uint errorPos) { protected void setError(int code, string message, uint errorLine, uint errorPos) {
_errorCode = code; _errorCode = code;
_errorMessage = message; _errorMessage = message;
_errorLine = errorLine; _errorLine = errorLine;
@ -166,9 +199,12 @@ class LineStream {
} }
// override to decode text // override to decode text
abstract uint decodeText(); protected abstract uint decodeText();
/// Unknown line position
immutable static uint LINE_POSITION_UNDEFINED = uint.max; immutable static uint LINE_POSITION_UNDEFINED = uint.max;
/// Read line from stream
public dchar[] readLine() { public dchar[] readLine() {
if (_errorCode != 0) { if (_errorCode != 0) {
//writeln("error ", _errorCode, ": ", _errorMessage, " in line ", _errorLine); //writeln("error ", _errorCode, ": ", _errorMessage, " in line ", _errorLine);
@ -250,11 +286,11 @@ class LineStream {
return _textBuf[lineStart .. lineEnd]; return _textBuf[lineStart .. lineEnd];
} }
immutable static int TEXT_BUFFER_SIZE = 1024; protected immutable static int TEXT_BUFFER_SIZE = 1024;
immutable static int BYTE_BUFFER_SIZE = 512; protected immutable static int BYTE_BUFFER_SIZE = 512;
immutable static int QUARTER_BYTE_BUFFER_SIZE = BYTE_BUFFER_SIZE / 4; protected immutable static int QUARTER_BYTE_BUFFER_SIZE = BYTE_BUFFER_SIZE / 4;
// factory for string parser /// Factory method for string parser
public static LineStream create(string code, string filename = "") { public static LineStream create(string code, string filename = "") {
uint len = cast(uint)code.length; uint len = cast(uint)code.length;
ubyte[] data = new ubyte[len + 3]; ubyte[] data = new ubyte[len + 3];
@ -268,7 +304,7 @@ class LineStream {
return create(stream, filename); return create(stream, filename);
} }
// factory /// Factory for InputStream parser
public static LineStream create(InputStream stream, string filename) { public static LineStream create(InputStream stream, string filename) {
ubyte[] buf = new ubyte[BYTE_BUFFER_SIZE]; ubyte[] buf = new ubyte[BYTE_BUFFER_SIZE];
buf[0] = buf[1] = buf[2] = buf[3] = 0; buf[0] = buf[1] = buf[2] = buf[3] = 0;
@ -293,13 +329,12 @@ class LineStream {
protected bool invalidCharFlag; protected bool invalidCharFlag;
protected void invalidCharError() { protected void invalidCharError() {
uint pos = _textLen - _textPos + 1; uint pos = _textLen - _textPos + 1;
setError(1, "Invalid character in line " ~ to!string(_line) ~ ":" ~ to!string(pos), _line, pos); setError(ErrorCodes.INVALID_CHARACTER, "Invalid character in line " ~ to!string(_line) ~ ":" ~ to!string(pos), _line, pos);
} }
} }
private class AsciiLineStream : LineStream {
class AsciiLineStream : LineStream {
this(InputStream stream, string filename, ubyte[] buf, uint len) { this(InputStream stream, string filename, ubyte[] buf, uint len) {
super(stream, filename, EncodingType.ASCII, buf, 0, len); super(stream, filename, EncodingType.ASCII, buf, 0, len);
} }
@ -332,7 +367,7 @@ class AsciiLineStream : LineStream {
} }
class Utf8LineStream : LineStream { private class Utf8LineStream : LineStream {
this(InputStream stream, string filename, ubyte[] buf, uint len) { this(InputStream stream, string filename, ubyte[] buf, uint len) {
super(stream, filename, EncodingType.UTF8, buf, 3, len); super(stream, filename, EncodingType.UTF8, buf, 3, len);
} }
@ -448,7 +483,7 @@ class Utf8LineStream : LineStream {
} }
} }
class Utf16beLineStream : LineStream { private class Utf16beLineStream : LineStream {
this(InputStream stream, string filename, ubyte[] buf, uint len) { this(InputStream stream, string filename, ubyte[] buf, uint len) {
super(stream, filename, EncodingType.UTF16BE, buf, 2, len); super(stream, filename, EncodingType.UTF16BE, buf, 2, len);
} }
@ -482,7 +517,7 @@ class Utf16beLineStream : LineStream {
} }
} }
class Utf16leLineStream : LineStream { private class Utf16leLineStream : LineStream {
this(InputStream stream, string filename, ubyte[] buf, uint len) { this(InputStream stream, string filename, ubyte[] buf, uint len) {
super(stream, filename, EncodingType.UTF16LE, buf, 2, len); super(stream, filename, EncodingType.UTF16LE, buf, 2, len);
} }
@ -516,7 +551,7 @@ class Utf16leLineStream : LineStream {
} }
} }
class Utf32beLineStream : LineStream { private class Utf32beLineStream : LineStream {
this(InputStream stream, string filename, ubyte[] buf, uint len) { this(InputStream stream, string filename, ubyte[] buf, uint len) {
super(stream, filename, EncodingType.UTF32BE, buf, 4, len); super(stream, filename, EncodingType.UTF32BE, buf, 4, len);
} }
@ -555,7 +590,7 @@ class Utf32beLineStream : LineStream {
} }
} }
class Utf32leLineStream : LineStream { private class Utf32leLineStream : LineStream {
this(InputStream stream, string filename, ubyte[] buf, uint len) { this(InputStream stream, string filename, ubyte[] buf, uint len) {
super(stream, filename, EncodingType.UTF32LE, buf, 4, len); super(stream, filename, EncodingType.UTF32LE, buf, 4, len);
} }

View File

@ -1,24 +1,28 @@
// Written in the D programming language. // Written in the D programming language.
/** /**
This module contains logger implementation. This module provides logging utilities.
Use Log class static methods.
Synopsis: Synopsis:
---- ----
import dlangui.core.logger; import dlangui.core.logger;
// setup:
// use stderror for logging // use stderror for logging
setStderrLogger(); setStderrLogger();
// set log level // set log level
setLogLevel(LogLeve.Debug); setLogLevel(LogLeve.Debug);
// usage:
// log debug message // log debug message
Log.d("mouse clicked at ", x, ",", y); Log.d("mouse clicked at ", x, ",", y);
// log error message // log error message
Log.d("exception while reading file", e); Log.e("exception while reading file", e);
---- ----
Copyright: Vadim Lopatin, 2014 Copyright: Vadim Lopatin, 2014
@ -30,40 +34,75 @@ module dlangui.core.logger;
import std.stdio; import std.stdio;
import std.datetime; import std.datetime;
/// Log levels
enum LogLevel : int { enum LogLevel : int {
/// Fatal error, cannot resume
Fatal, Fatal,
/// Error
Error, Error,
/// Warning
Warn, Warn,
/// Informational message
Info, Info,
/// Debug message
Debug, Debug,
/// Tracing message
Trace Trace
} }
/// Returns timestamp in milliseconds since 1970 UTC similar to Java System.currentTimeMillis()
long currentTimeMillis() { long currentTimeMillis() {
return std.datetime.Clock.currStdTime / 10000; return std.datetime.Clock.currStdTime / 10000;
} }
/**
Logging utilities
Setup example:
----
// setup:
// use stderror for logging
setStderrLogger();
// set log level
setLogLevel(LogLeve.Debug);
----
Logging example:
----
// log debug message
Log.d("mouse clicked at ", x, ",", y);
// log error message
Log.e("exception while reading file", e);
----
*/
synchronized class Log { synchronized class Log {
static { static:
private LogLevel logLevel = LogLevel.Info; private LogLevel logLevel = LogLevel.Info;
private std.stdio.File logFile; private std.stdio.File logFile;
/// Redirects output to stdout
void setStdoutLogger() { void setStdoutLogger() {
logFile = stdout; logFile = stdout;
} }
/// Redirects output to stderr
void setStderrLogger() { void setStderrLogger() {
logFile = stderr; logFile = stderr;
} }
/// Redirects output to file
void setFileLogger(File file) { void setFileLogger(File file) {
logFile = file; logFile = file;
} }
/// Sets log level (one of LogLevel)
void setLogLevel(LogLevel level) { void setLogLevel(LogLevel level) {
logLevel = level; logLevel = level;
} }
/// Log level to name helper function
string logLevelName(LogLevel level) { string logLevelName(LogLevel level) {
switch (level) { switch (level) {
case LogLevel.Fatal: return "F"; case LogLevel.Fatal: return "F";
@ -75,6 +114,7 @@ synchronized class Log {
default: return "?"; default: return "?";
} }
} }
/// Log message with arbitrary log level
void log(S...)(LogLevel level, S args) { void log(S...)(LogLevel level, S args) {
if (logLevel >= level && logFile.isOpen) { if (logLevel >= level && logFile.isOpen) {
SysTime ts = Clock.currTime(); SysTime ts = Clock.currTime();
@ -83,29 +123,34 @@ synchronized class Log {
logFile.flush(); logFile.flush();
} }
} }
/// Log verbose / trace message
void v(S...)(S args) { void v(S...)(S args) {
if (logLevel >= LogLevel.Trace && logFile.isOpen) if (logLevel >= LogLevel.Trace && logFile.isOpen)
log(LogLevel.Trace, args); log(LogLevel.Trace, args);
} }
/// Log debug message
void d(S...)(S args) { void d(S...)(S args) {
if (logLevel >= LogLevel.Debug && logFile.isOpen) if (logLevel >= LogLevel.Debug && logFile.isOpen)
log(LogLevel.Debug, args); log(LogLevel.Debug, args);
} }
/// Log info message
void i(S...)(S args) { void i(S...)(S args) {
if (logLevel >= LogLevel.Info && logFile.isOpen) if (logLevel >= LogLevel.Info && logFile.isOpen)
log(LogLevel.Info, args); log(LogLevel.Info, args);
} }
/// Log warn message
void w(S...)(S args) { void w(S...)(S args) {
if (logLevel >= LogLevel.Warn && logFile.isOpen) if (logLevel >= LogLevel.Warn && logFile.isOpen)
log(LogLevel.Warn, args); log(LogLevel.Warn, args);
} }
/// Log error message
void e(S...)(S args) { void e(S...)(S args) {
if (logLevel >= LogLevel.Error && logFile.isOpen) if (logLevel >= LogLevel.Error && logFile.isOpen)
log(LogLevel.Error, args); log(LogLevel.Error, args);
} }
/// Log fatal error message
void f(S...)(S args) { void f(S...)(S args) {
if (logLevel >= LogLevel.Fatal && logFile.isOpen) if (logLevel >= LogLevel.Fatal && logFile.isOpen)
log(LogLevel.Fatal, args); log(LogLevel.Fatal, args);
} }
} }
}