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.
/**
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).
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:
@ -44,7 +62,12 @@ private import dlangui.core.linestream;
private import std.utf;
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 {
/** if not null, use it, otherwise lookup by id */
private dstring _value;
@ -61,13 +84,14 @@ struct UIString {
}
/// Returns string resource id
@property string id() const { return _id; }
/// Sets string resource id
@property void id(string ID) {
_id = ID;
_value = null;
}
/** get value (either raw or translated by id) */
/** Get value (either raw or translated by id) */
@property dstring value() const {
if (_value !is null)
return _value;
@ -76,55 +100,59 @@ struct UIString {
// translate ID to dstring
return i18n.get(_id);
}
/** set raw value */
/** Set raw value using property */
@property void value(dstring newValue) {
_value = newValue;
}
/** assign raw value */
/** Assign raw value */
ref UIString opAssign(dstring rawValue) {
_value = rawValue;
_id = null;
return this;
}
/** assign ID */
/** Assign string resource id */
ref UIString opAssign(string ID) {
_id = ID;
_value = null;
return this;
}
/** default conversion to dstring */
/** Default conversion to dstring */
alias value this;
}
/** UIString item collection. */
/**
UIString item collection
Based on array.
*/
struct UIStringCollection {
private UIString[] _items;
private int _length;
/** returns number of items */
/** Returns number of items */
@property int length() { return _length; }
/** slice */
/** Slice */
UIString[] opIndex() {
return _items[0 .. _length];
}
/** slice */
/** Slice */
UIString[] opSlice() {
return _items[0 .. _length];
}
/** slice */
/** Slice */
UIString[] opSlice(size_t start, size_t end) {
return _items[start .. end];
}
/** read item by index */
/** Read item by index */
UIString opIndex(size_t index) {
return _items[index];
}
/** modify item by index */
/** Modify item by index */
UIString opIndexAssign(UIString value, size_t index) {
_items[index] = value;
return _items[index];
}
/** return unicode string for item by index */
/** Return unicode string for item by index */
dstring get(size_t index) {
return _items[index].value;
}
@ -161,7 +189,7 @@ struct UIStringCollection {
add(item);
}
}
/** remove all items */
/** Remove all items */
void clear() {
_items.length = 0;
_length = 0;
@ -226,14 +254,14 @@ struct UIStringCollection {
}
}
/** UI Strings internationalization translator. */
/** UI Strings internationalization translator */
synchronized class UIStringTranslator {
private UIStringList _main;
private UIStringList _fallback;
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 ...) {
_resourceDirs.length = 0;
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) {
if (filename is null)
return null;
@ -264,12 +292,13 @@ synchronized class UIStringTranslator {
return res;
}
/// create empty translator
this() {
_main = new shared UIStringList();
_fallback = new shared UIStringList();
}
/** load translation file(s) */
/** Load translation file(s) */
bool load(string mainFilename, string fallbackFilename = null) {
_main.clear();
_fallback.clear();
@ -280,7 +309,7 @@ synchronized class UIStringTranslator {
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) {
if (id is null)
return null;
@ -365,7 +394,7 @@ private shared class UIStringList {
}
}
/** Global translator object. */
/** Global UI translator object */
shared UIStringTranslator i18n;
shared static this() {
i18n = new shared UIStringTranslator();

View File

@ -1,7 +1,10 @@
// 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.
@ -51,44 +54,74 @@ import std.stream;
import std.stdio;
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 {
/// File encoding
public enum EncodingType {
/// plaing ASCII (character codes must be <= 127)
ASCII,
/// utf-8 unicode
UTF8,
/// utf-16 unicode big endian
UTF16BE,
/// utf-16 unicode little endian
UTF16LE,
/// utf-32 unicode big endian
UTF32BE,
/// utf-32 unicode little endian
UTF32LE
};
InputStream _stream;
string _filename;
ubyte[] _buf; // stream reading buffer
uint _pos; // reading position of stream buffer
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
uint _textLen; // position of last filled char in text buffer + 1
dchar[] _textBuf; // text buffer
bool _eof; // end of file, no more lines
/// Error codes
public enum ErrorCodes {
/// invalid character for current encoding
INVALID_CHARACTER
};
private InputStream _stream;
private string _filename;
private ubyte[] _buf; // stream reading buffer
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; }
/// Returns current line number
@property uint line() { return _line; }
/// Returns file encoding EncodingType
@property EncodingType encoding() { return _encoding; }
/// Returns error code
@property int errorCode() { return _errorCode; }
/// Returns error message
@property string errorMessage() { return _errorMessage; }
/// Returns line where error is found
@property int errorLine() { return _errorLine; }
/// Returns line position (number of character in line) where error is found
@property int errorPos() { return _errorPos; }
immutable EncodingType _encoding;
private immutable EncodingType _encoding;
int _errorCode;
string _errorMessage;
uint _errorLine;
uint _errorPos;
private int _errorCode;
private string _errorMessage;
private uint _errorLine;
private uint _errorPos;
/// Open file with known encoding
protected this(InputStream stream, string filename, EncodingType encoding, ubyte[] buf, uint offset, uint len) {
_filename = filename;
_stream = stream;
@ -99,8 +132,8 @@ class LineStream {
_streamEof = _stream.eof;
}
// returns slice of bytes available in buffer
uint readBytes() {
/// returns slice of bytes available in buffer
protected uint readBytes() {
uint bytesLeft = _len - _pos;
if (_streamEof || bytesLeft > QUARTER_BYTE_BUFFER_SIZE)
return bytesLeft;
@ -117,12 +150,12 @@ class LineStream {
}
// when bytes consumed from byte buffer, call this method to update position
void consumedBytes(uint count) {
protected void consumedBytes(uint count) {
_pos += count;
}
// 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
if (_textBuf == null) {
if (len < TEXT_BUFFER_SIZE)
@ -153,12 +186,12 @@ class LineStream {
return _textBuf.ptr + _textLen;
}
void appendedText(uint len) {
protected void appendedText(uint len) {
//writeln("appended ", len, " chars of text"); //:", _textBuf[_textLen .. _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;
_errorMessage = message;
_errorLine = errorLine;
@ -166,9 +199,12 @@ class LineStream {
}
// override to decode text
abstract uint decodeText();
protected abstract uint decodeText();
/// Unknown line position
immutable static uint LINE_POSITION_UNDEFINED = uint.max;
/// Read line from stream
public dchar[] readLine() {
if (_errorCode != 0) {
//writeln("error ", _errorCode, ": ", _errorMessage, " in line ", _errorLine);
@ -250,11 +286,11 @@ class LineStream {
return _textBuf[lineStart .. lineEnd];
}
immutable static int TEXT_BUFFER_SIZE = 1024;
immutable static int BYTE_BUFFER_SIZE = 512;
immutable static int QUARTER_BYTE_BUFFER_SIZE = BYTE_BUFFER_SIZE / 4;
protected immutable static int TEXT_BUFFER_SIZE = 1024;
protected immutable static int BYTE_BUFFER_SIZE = 512;
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 = "") {
uint len = cast(uint)code.length;
ubyte[] data = new ubyte[len + 3];
@ -268,7 +304,7 @@ class LineStream {
return create(stream, filename);
}
// factory
/// Factory for InputStream parser
public static LineStream create(InputStream stream, string filename) {
ubyte[] buf = new ubyte[BYTE_BUFFER_SIZE];
buf[0] = buf[1] = buf[2] = buf[3] = 0;
@ -293,13 +329,12 @@ class LineStream {
protected bool invalidCharFlag;
protected void invalidCharError() {
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);
}
}
class AsciiLineStream : LineStream {
private class AsciiLineStream : LineStream {
this(InputStream stream, string filename, ubyte[] buf, uint 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) {
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) {
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) {
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) {
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) {
super(stream, filename, EncodingType.UTF32LE, buf, 4, len);
}

View File

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