PageRenderTime 39ms CodeModel.GetById 19ms app.highlight 15ms RepoModel.GetById 2ms app.codeStats 0ms

/src/i18n/z_trans.erl

https://code.google.com/p/zotonic/
Erlang | 222 lines | 148 code | 32 blank | 42 comment | 0 complexity | 2a00f4852e5f01ea216a512745271dd5 MD5 | raw file
  1%% @author Marc Worrell <marc@worrell.nl>
  2%% @copyright 2009 Marc Worrell
  3%% @doc Translate english sentences into other languages, following
  4%% the GNU gettext principle.
  5
  6%% Copyright 2009 Marc Worrell
  7%%
  8%% Licensed under the Apache License, Version 2.0 (the "License");
  9%% you may not use this file except in compliance with the License.
 10%% You may obtain a copy of the License at
 11%% 
 12%%     http://www.apache.org/licenses/LICENSE-2.0
 13%% 
 14%% Unless required by applicable law or agreed to in writing, software
 15%% distributed under the License is distributed on an "AS IS" BASIS,
 16%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 17%% See the License for the specific language governing permissions and
 18%% limitations under the License.
 19
 20-module(z_trans).
 21-author("Marc Worrell <marc@worrell.nl>").
 22
 23-export([
 24    translations/2,
 25    parse_translations/1,
 26    trans/2,
 27    lookup/2,
 28    lookup/3,
 29    lookup_fallback/2,
 30    lookup_fallback/3,
 31    default_language/1, 
 32    is_language/1, 
 33    language_list/1,
 34    lc2/1, 
 35    lc2descr/1
 36]).
 37
 38-include_lib("zotonic.hrl").
 39
 40
 41%% @doc Fetch all translations for the given string.
 42%% @spec translations(From, Context) -> #trans{} | binary()
 43translations({trans, Tr0} = Trans0, Context) ->
 44    {en, From} = proplists:lookup(en, Tr0),
 45    case translations(From, Context) of
 46        {trans, Tr1} -> merge_trs(Tr0, Tr1);
 47        _ -> Trans0
 48    end;
 49translations(From, Context) when is_binary(From) ->
 50    case ets:lookup(z_trans_server:table(Context), From) of
 51        [] ->
 52			From;
 53        [{_, Trans}] ->
 54			{trans, Trans}
 55    end;
 56translations(From, Context) ->
 57    translations(z_convert:to_binary(From), Context).
 58
 59    merge_trs([], Acc) ->
 60        Acc;
 61    merge_trs([{Lang,_} = LT|Rest], Acc) ->
 62        case proplists:is_defined(Lang, Acc) of
 63            true -> merge_trs(Rest, Acc);
 64            false -> merge_trs(Rest, [LT|Acc])
 65        end.
 66
 67%% @doc Prepare a translations table based on all .po files in the active modules.
 68parse_translations(Context) ->
 69    Mods = z_module_indexer:translations(Context),
 70    build_index(parse_mod_trans(Mods, []), dict:new()).
 71
 72    %% @doc Parse all .po files. Results in a dict {label, [iso_code,trans]}
 73    parse_mod_trans([], Acc) ->
 74        lists:reverse(Acc);
 75    parse_mod_trans([{_Module, {_Dir, Trans}}|Rest], Acc) ->
 76        Acc1 = parse_trans(Trans, Acc),
 77        parse_mod_trans(Rest, Acc1).
 78    
 79    parse_trans([], Acc) ->
 80        Acc;
 81    parse_trans([{Lang,File}|Rest], Acc) ->
 82        parse_trans(Rest, [{Lang, z_gettext:parse_po(File)}|Acc]).
 83    
 84    build_index([], Dict) ->
 85        Dict;
 86    build_index([{Lang, Labels}|Rest], Dict) ->
 87        build_index(Rest, add_labels(Lang, Labels, Dict)).
 88    
 89    add_labels(_Lang, [], Dict) ->
 90        Dict;
 91    add_labels(Lang, [{header,_}|Rest],Dict) ->
 92        add_labels(Lang, Rest,Dict);
 93    add_labels(Lang, [{Label,Trans}|Rest], Dict) ->
 94        LabelB = list_to_binary(Label),
 95        case dict:find(LabelB, Dict) of
 96            {ok, Ts} ->
 97                case proplists:get_value(Lang, Ts) of
 98                    undefined -> add_labels(Lang, Rest, dict:store(LabelB, [{Lang,list_to_binary(Trans)}|Ts], Dict));
 99                    _PrevTrans -> add_labels(Lang, Rest, Dict)
100                end;
101            error -> 
102                add_labels(Lang, Rest, dict:store(LabelB,[{Lang,to_binary(Trans)}],Dict))
103        end.
104        
105        to_binary(header) -> "";
106        to_binary(L) -> list_to_binary(L).
107            
108
109
110%% @doc Strict translation lookup of a language version
111lookup(Trans, Context) ->
112    lookup(Trans, z_context:language(Context), Context).
113    
114lookup({trans, Tr}, Lang, _Context) ->
115    proplists:get_value(Lang, Tr);
116lookup(Text, Lang, Context) ->
117    case z_context:language(Context) of
118        Lang -> Text;
119        _ -> undefined
120    end.
121
122%% @doc Non strict translation lookup of a language version.
123%%      In order check: requested language, default configured language, english, any
124lookup_fallback(Trans, Context) ->
125    lookup_fallback(Trans, z_context:language(Context), Context).
126
127lookup_fallback({trans, Tr}, Lang, Context) ->
128    case proplists:get_value(Lang, Tr) of
129        undefined ->
130            case default_language(Context) of
131                undefined -> take_english_or_first(Tr);
132                CfgLang ->
133                    case proplists:get_value(z_convert:to_atom(CfgLang), Tr) of
134                        undefined -> take_english_or_first(Tr);
135                        Text -> Text
136                    end
137            end;
138        Text -> 
139            Text
140    end;
141lookup_fallback(Text, _Lang, _Context) ->
142    Text.
143    
144    take_english_or_first(Tr) ->
145        case proplists:get_value(en, Tr) of
146            undefined ->
147                case Tr of
148                    [{_,Text}|_] -> Text;
149                    _ -> undefined
150                end;
151            EnglishText -> 
152                EnglishText
153        end.
154
155
156%% @doc translate a string or trans record into another language
157%% @spec trans(From, Language) -> String
158%%   From = #trans{} | String
159%%   Language = atom()
160trans({trans, Tr}, Lang) when is_atom(Lang) ->
161    proplists:get_value(Lang, Tr);
162trans(Text, Lang) when is_atom(Lang) ->
163    Text;
164trans(Text, Context) ->
165    trans(Text, Context#context.language, Context).
166
167trans({trans, Tr0}, Language, Context) ->
168    case proplists:lookup(en, Tr0) of
169        {en, Text} ->
170            case translations(Text, Context) of
171                {trans, Tr} ->
172                    case proplists:get_value(Language, Tr) of
173                        undefined -> proplists:get_value(Language, Tr0, Text);
174                        Translated -> Translated
175                    end;
176                _ ->
177                    proplists:get_value(Language, Tr0, Text)
178            end;
179        none ->
180            proplists:get_value(Language, Tr0)
181    end;
182trans(Text, Language, Context) ->
183    case translations(Text, Context) of
184        {trans, Tr} ->
185            proplists:get_value(Language, Tr, Text);
186        _ -> Text
187    end.
188
189
190%% @doc Return the configured default language for this server
191default_language(Context) ->
192    z_convert:to_atom(m_config:get_value(i18n, language, en, Context)).
193
194
195%% @doc Return the list of languages selected for this site
196%% @todo Make this configurable
197language_list(_Context) ->
198    [ en, nl ].
199
200%% @doc check if the two letter code is a valid language
201%% @spec is_language(LanguageString) -> bool()
202%%   LanguageString = string()
203is_language(LanguageString) ->
204	Language = iso639:lc2lang(LanguageString),
205	Language /= "".
206	
207
208%% @doc Translate a language to an atom, fail when unknown language
209%% @spec lc2(LanguageString) -> Language
210%%  LanguageString = string()
211%%  Language = atom()
212lc2(LanguageString) ->
213	true = is_language(iso639:lc2lang(LanguageString)),
214	list_to_atom(LanguageString).
215
216
217%% @doc Return a descriptive (english) string for the language
218%% @spec lc2descr(Language) -> Descr
219%%  Language = atom()
220%%  Descr = list()
221lc2descr(Language) ->
222	iso639:lc2lang(atom_to_list(Language)).