Permalink
Newer
Older
100644 214 lines (193 sloc) 5.64 KB
Jan 1, 2008
1
%%
2
%% wings_lang.erl --
3
%%
4
%% Implementation of languages.
5
%%
6
%% Copyright (c) 2004 Riccardo Venier, Dan Gudmundsson
7
%% 2004-2009 Dan Gudmundsson, Bjorn Gustavsson
Jan 1, 2008
8
%%
9
%% See the file "license.terms" for information on usage and redistribution
10
%% of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11
%%
12
%% $Id$
13
%%
14
%% Totally rewritten but Riccardo is still the one who did the hard work.
15
%%
16
17
-module(wings_lang).
18
19
%% Wings API.
20
-export([init/0,str/2,
21
available_languages/0,load_language/1]).
22
23
-import(lists, [reverse/1,foreach/2]).
Jan 1, 2008
24
25
-define(DEF_LANG_STR, "en"). % English
26
-define(DEF_LANG_ATOM, en). % English
27
-define(LANG_DIRS, ["ebin","src","plugins","plugins_src"]).
28
29
str({_,_,_}=Key, DefStr) ->
30
case get(?MODULE) of
31
?DEF_LANG_ATOM -> DefStr;
32
_ ->
33
try ets:lookup_element(?MODULE, Key, 2) of
34
Str when is_binary(Str) -> binary_to_list(Str);
35
Str when is_list(Str) -> Str
36
catch
37
error:_ -> DefStr
38
end
39
end.
40
41
init() ->
42
wings_pref:set_default(language, ?DEF_LANG_STR),
43
Lang = case wings_pref:get_value(language) of
44
?DEF_LANG_STR=L -> L;
45
Other ->
46
case lists:member(Other, available_languages()) of
47
true -> Other;
48
false -> ?DEF_LANG_STR
49
end
50
end,
51
load_language_only(Lang).
52
53
load_language(Lang) when is_list(Lang) ->
54
load_language_only(Lang),
55
wings:init_menubar(),
56
foreach(fun(W) -> wings_wm:send(W, language_changed) end,
57
wings_wm:windows()).
58
59
load_language_only(Lang0) when is_list(Lang0) ->
60
Lang = list_to_atom(Lang0),
61
put(?MODULE, Lang),
62
catch ets:delete(?MODULE),
63
case Lang of
64
?DEF_LANG_ATOM -> ok;
65
_ ->
66
ets:new(?MODULE, [named_table]),
67
Root = wings_util:lib_dir(wings),
68
LangFile = "_"++Lang0++".lang",
69
load_language(Root, ?LANG_DIRS, LangFile)
70
end.
71
72
load_language(_, [],_) -> ok;
73
load_language(Root, [Dir|Dirs], Lang) ->
74
Path = filename:join(Root, Dir),
75
case file:list_dir(Path) of
76
{ok,List} ->
77
load_language_2(Path, List, Lang),
78
load_language(Root,Dirs,Lang);
79
_ ->
80
load_language(Root,Dirs, Lang)
81
end.
82
83
load_language_2(Dir, [File|Fs], Lang) ->
84
case catch lists:nthtail(length(File)-length(Lang), File) of
85
Lang ->
86
load_language_file(filename:join(Dir, File));
87
_ ->
88
Path = filename:join(Dir,File),
89
case filelib:is_dir(Path) of
90
true ->
91
load_language(Dir, [File], Lang);
92
false ->
93
ignore
94
end
95
end,
96
load_language_2(Dir, Fs, Lang);
97
load_language_2(_, [], _) -> ok.
98
99
load_language_file(File) ->
100
case file:consult(File) of
101
{ok,Terms} ->
102
io:format("Loading ~s\n", [File]),
103
load_file(Terms);
104
{error,{Line,Mod,Info}} ->
105
io:format("~s, line ~p: ~s\n",
106
[File,Line,Mod:format_error(Info)]);
107
Other ->
108
io:format("Problem reading language file ~p:\n~p\n",
109
[File,Other])
110
end.
111
112
load_file([utf8|Trans]) ->
113
load_file_1(utf8, Trans);
114
load_file([latin1|Trans]) ->
115
load_file_1(latin1, Trans);
116
load_file(['iso-8859-1'|Trans]) ->
117
load_file_1(latin1, Trans);
118
load_file([Atom|Trans]) when is_atom(Atom) ->
Jan 1, 2008
119
io:format("Ignoring: ~p\n", [Atom]),
120
load_file_1(default, Trans);
121
load_file(Trans) -> load_file_1(default, Trans).
122
123
load_file_1(latin1, Trans) ->
124
%% ISO-8859-1/Latin 1: Just load the file without any transformation.
125
io:format(" encoding: latin1\n"),
126
load_file_2(Trans);
127
load_file_1(utf8, Trans0) ->
128
%% UTF8: Transform the file; abort loading if any failures.
129
case expand_utf8(Trans0) of
130
Trans when is_list(Trans) ->
131
io:format(" encoding: utf8\n"),
132
load_file_2(Trans);
133
{error,{Mod,Name,Key}} ->
134
%% Abort loading.
135
io:format("Bad UTF-8 string for module=~p, function=~p, key=~p\n",
136
[Mod,Name,Key])
137
end;
138
load_file_1(default, Trans0) ->
139
%% Default: Try UTF8 transformation first, fall back to no transformation
140
%% if it fails.
141
case expand_utf8(Trans0) of
142
Trans when is_list(Trans) ->
143
io:format(" encoding: utf8 or plain US-ASCII\n"),
144
load_file_2(Trans);
145
{error,_} ->
146
%% Just load it.
147
io:format(" encoding: probably latin1\n"),
148
load_file_2(Trans0)
149
end.
150
151
load_file_2(Trans) ->
152
Add = fun(Level, Str0) ->
153
Key = list_to_tuple(reverse(Level)),
154
Str = try
155
list_to_binary(Str0)
156
catch
157
error:badarg -> Str0
158
end,
159
ets:insert(?MODULE, {Key,Str})
160
end,
161
Trav =
162
fun(Data = [Cont|_], Level, Trav) when is_tuple(Cont) ->
163
Insert = fun({Key, Next}) ->
164
Trav(Next, [Key|Level], Trav)
165
end,
166
lists:foreach(Insert, Data);
167
(Str, Level, _) ->
168
Add(Level,Str)
169
end,
170
Trav(Trans,[],Trav).
171
172
available_languages() ->
173
Root = wings_util:lib_dir(wings),
174
Files =
175
filelib:wildcard(filename:join([Root,"src","*.lang"])) ++
176
filelib:wildcard(filename:join([Root,"ebin","*.lang"])),
177
Extract = fun(File, Acc) ->
178
BaseName = filename:basename(File),
179
case string:tokens(filename:rootname(BaseName),[$_]) of
180
[_Name,Lang] -> [Lang|Acc];
181
_ -> Acc
182
end
183
end,
184
lists:usort([?DEF_LANG_STR|lists:foldl(Extract, [], Files)]).
185
186
%%%
187
%%% Character transformation support.
188
%%%
189
190
expand_utf8(ModFs) ->
191
try
192
expand_utf8_0(ModFs)
193
catch
194
throw:{error,_}=E ->
195
E
196
end.
197
198
expand_utf8_0([{Mod,Fs}|ModFs]) ->
199
[{Mod,expand_utf8_1(Fs, Mod)}|expand_utf8_0(ModFs)];
200
expand_utf8_0([]) -> [].
201
202
expand_utf8_1([{Name,Ss}|T], Mod) ->
203
[{Name,expand_utf8_2(Ss, Mod, Name)}|expand_utf8_1(T, Mod)];
204
expand_utf8_1([], _) -> [].
205
206
expand_utf8_2([{Key,Str0}|T], Mod, Name) ->
207
case unicode:characters_to_list(list_to_binary(Str0)) of
208
{error,_,_} ->
209
throw({error,{Mod,Name,Key}});
210
Str when is_list(Str) ->
211
[{Key,Str}|expand_utf8_2(T, Mod, Name)]
Jan 1, 2008
212
end;
213
expand_utf8_2([], _, _) -> [].