Compare commits

..

No commits in common. "master" and "v1.0.4" have entirely different histories.

13 changed files with 398 additions and 536 deletions

View file

@ -6,7 +6,7 @@ A Clojure library designed to provide simple interationalisation of user-facing
To use this library in your project, add the following leiningen dependency:
[org.clojars.simon_brooke/internationalisation "1.0.5"]
[org.clojars.simon_brooke/internationalisation "1.0.4"]
To use it in your namespace, require:
@ -62,21 +62,21 @@ For example:
(get-message :pipe "de-DE" "i18n" "ru")
```
So how does this work? When one calls
`(get-message token accept-language-header)`, how does it know where to find resources? The answer is that there is a `*config*` map, with (currently) two significant keys:
So how does this work? When one calls `(get-message token accept-language-header)`, how does it know where to find resources? The answer is that there are two dynamic variables:
* `:resource-path`, whose value should be a string representation of the default
path within the resources space on which translation files will be sought. Initialised to `i18n`.
* `:default-language`, the language tag for the language to use when no
* `*resource-path*`, the default path within the resources space on which
translation files will be sought. Initialised to `i18n`.
* `*default-language*`, the language tag for the language to use when no
otherwise suitable language can be identified. Initialised to the default
language of the runtime session, so this may well be different on your
machine from someone elses running identical software.
Thus
```clojure
(binding [*config* {:resource-path "language-files"
:default-language "en-CA"}]
(get-message :pipe "en-GB;q=0.9, fr-FR"))
(binding [*resource-path* "language-files"
*default-language* "en-CA"]
(get-message :pipe "en-GB;q=0.9, fr-FR")
)
```
and
```clojure
@ -116,27 +116,10 @@ In this project you will find two very simple example files, which should give y
## Documentation
Documentation can be found here. It may be generated by running
Documentation may be generated by running
lein codox
## Future direction
It's likely that in future configuration will be extended
1. To read per-language keys/messages from CSV files;
2. To read per-language keys/messages from database tables;
3. potentially, to read per-language keys/messages from other sources.
Pull requests implementing any of these things will be welcomed.
## Deprecated features
There are still two dynamic configuration variables, `*default-language*`
and `*resource-path*`, but these are now superceded by the `*config*` map,
which is extensible. Consequently, if you are using these configuration
variables in production, you should bind `*config*` to `nil`.
## License
Copyright © 2017 Simon Brooke

View file

@ -6,7 +6,7 @@ A Clojure library designed to provide simple interationalisation of user-facing
To use this library in your project, add the following leiningen dependency:
[org.clojars.simon_brooke/internationalisation "1.0.5"]
[org.clojars.simon_brooke/internationalisation "1.0.4"]
To use it in your namespace, require:
@ -62,21 +62,21 @@ For example:
(get-message :pipe "de-DE" "i18n" "ru")
```
So how does this work? When one calls
`(get-message token accept-language-header)`, how does it know where to find resources? The answer is that there is a `*config*` map, with (currently) two significant keys:
So how does this work? When one calls `(get-message token accept-language-header)`, how does it know where to find resources? The answer is that there are two dynamic variables:
* `:resource-path`, whose value should be a string representation of the default
path within the resources space on which translation files will be sought. Initialised to `i18n`.
* `:default-language`, the language tag for the language to use when no
* `*resource-path*`, the default path within the resources space on which
translation files will be sought. Initialised to `i18n`.
* `*default-language*`, the language tag for the language to use when no
otherwise suitable language can be identified. Initialised to the default
language of the runtime session, so this may well be different on your
machine from someone elses running identical software.
Thus
```clojure
(binding [*config* {:resource-path "language-files"
:default-language "en-CA"}]
(get-message :pipe "en-GB;q=0.9, fr-FR"))
(binding [*resource-path* "language-files"
*default-language* "en-CA"]
(get-message :pipe "en-GB;q=0.9, fr-FR")
)
```
and
```clojure
@ -116,27 +116,10 @@ In this project you will find two very simple example files, which should give y
## Documentation
Documentation can be found here. It may be generated by running
Documentation may be generated by running
lein codox
## Future direction
It's likely that in future configuration will be extended
1. To read per-language keys/messages from CSV files;
2. To read per-language keys/messages from database tables;
3. potentially, to read per-language keys/messages from other sources.
Pull requests implementing any of these things will be welcomed.
## Deprecated features
There are still two dynamic configuration variables, `*default-language*`
and `*resource-path*`, but these are now superceded by the `*config*` map,
which is extensible. Consequently, if you are using these configuration
variables in production, you should bind `*config*` to `nil`.
## License
Copyright © 2017 Simon Brooke

View file

@ -2,19 +2,17 @@
{"scot/weft/i18n/core.clj":
[null, 1, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, 1,
null, null, null, null, 1, null, 1, null, 1, null, 1, null, null, 1,
null, null, null, null, null, null, null, null, null, null, null,
null, 1, null, 1, null, 1, null, null, null, null, null, true, 159,
null, true, 159, 11, 22, 22, 22, 9, null, 24, 24, null, 24, 24, 10,
null, 25, 25, 20, 20, null, 20, 5, 26, 20, 20, 0, 0, null, 0, 20,
20, null, 11, null, 0, 0, null, null, 1, null, null, null, null,
null, null, null, null, 10, 10, 10, 10, null, 10, 10, 0, null, null,
1, null, null, null, 24, 24, null, 11, null, null, null, 1, null,
null, null, null, null, null, null, null, null, null, 25, 25, 15,
15, 15, 25, 25, 25, 6, 19, 10, 10, 10, 10, 5, 5, 5, null, null, 1,
null, null, null, null, null, null, null, null, null, null, null,
null, null, 9, 9, 9, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, true, 7,
null, 0, 0, 0, null, null, 2, 2, null, null, 1, null, null, null,
null, null, null, null, null, null, 1, null, 1, null, null, null,
null, null, null, null, null, null, null, 1, 8, 8, null, 7, 7, 7, 7,
null, 5, 5]}}
null, null, null, null, 1, null, 1, null, 1, null, null, null, null,
null, null, null, null, null, null, null, null, 1, null, 1, null, 1,
null, null, null, null, null, true, 119, null, true, 119, 6, 16, 16,
16, 8, null, 18, 18, null, 18, 18, 9, null, 19, 19, 15, 15, null,
15, 4, 20, 15, 15, 0, 0, null, 0, 15, 15, null, 10, null, 0, 0,
null, null, 1, null, null, null, null, null, null, null, null, 6, 6,
5, 5, null, 5, 5, 1, null, null, 1, null, null, null, 13, 13, null,
7, null, null, null, 1, null, null, null, null, null, null, null,
null, null, null, 13, 13, 8, 8, 8, 13, 13, 13, 2, 11, 5, 5, 5, 5, 3,
3, 3, null, null, 1, null, null, null, null, null, null, null, null,
null, null, null, null, null, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3,
3, 3, null, 1, null, null, 1, null, null, null, null, null, null,
null, null, null, 1, null, 1, null, null, null, null, null, null,
null, null, null, 1, 3, null, 1, null, 1]}}

View file

@ -1 +1 @@
<?xml version="1.0" encoding="UTF-8"?><report><stats><packages value="1"/><methods value="413"/><srcfiles value="1"/><srclines value="106"/></stats><data><all name="total"><coverage type="class, %" value="0% (0/1)"/><coverage type="method, %" value="0% (0/1)"/><coverage type="block, %" value="82% (338/413)"/><coverage type="line, %" value="89% (94/106)"/><package name="scot.weft.i18n.core"><coverage type="class, %" value="0% (0/1)"/><coverage type="method, %" value="0% (0/1)"/><coverage type="block, %" value="82% (338/413)"/><coverage type="line, %" value="89% (94/106)"/></package></all></data></report>
<?xml version="1.0" encoding="UTF-8"?><report><stats><packages value="1"/><methods value="367"/><srcfiles value="1"/><srclines value="93"/></stats><data><all name="total"><coverage type="class, %" value="0% (0/1)"/><coverage type="method, %" value="0% (0/1)"/><coverage type="block, %" value="91% (333/367)"/><coverage type="line, %" value="92% (86/93)"/><package name="scot.weft.i18n.core"><coverage type="class, %" value="0% (0/1)"/><coverage type="method, %" value="0% (0/1)"/><coverage type="block, %" value="91% (333/367)"/><coverage type="line, %" value="92% (86/93)"/></package></all></data></report>

View file

@ -16,26 +16,26 @@
</tr></thead>
<tr>
<td><a href="scot/weft/i18n/core.clj.html">scot.weft.i18n.core</a></td><td class="with-bar"><div class="covered"
style="width:81.84019370460048%;
float:left;"> 338 </div><div class="not-covered"
style="width:18.159806295399516%;
float:left;"> 75 </div></td>
<td class="with-number">81.84 %</td>
style="width:90.73569482288828%;
float:left;"> 333 </div><div class="not-covered"
style="width:9.264305177111716%;
float:left;"> 34 </div></td>
<td class="with-number">90.74 %</td>
<td class="with-bar"><div class="covered"
style="width:88.67924528301887%;
float:left;"> 94 </div><div class="partial"
style="width:2.830188679245283%;
float:left;"> 3 </div><div class="not-covered"
style="width:8.49056603773585%;
float:left;"> 9 </div></td>
<td class="with-number">91.51 %</td>
<td class="with-number">235</td><td class="with-number">24</td><td class="with-number">106</td>
style="width:92.47311827956989%;
float:left;"> 86 </div><div class="partial"
style="width:2.150537634408602%;
float:left;"> 2 </div><div class="not-covered"
style="width:5.376344086021505%;
float:left;"> 5 </div></td>
<td class="with-number">94.62 %</td>
<td class="with-number">216</td><td class="with-number">23</td><td class="with-number">93</td>
</tr>
<tr><td>Totals:</td>
<td class="with-bar"></td>
<td class="with-number">81.84 %</td>
<td class="with-number">90.74 %</td>
<td class="with-bar"></td>
<td class="with-number">91.51 %</td>
<td class="with-number">94.62 %</td>
</tr>
</table>
</body>

View file

@ -77,7 +77,7 @@
024&nbsp;&nbsp;&nbsp;&nbsp;&quot;The&nbsp;default&nbsp;path&nbsp;within&nbsp;the&nbsp;resources&nbsp;space&nbsp;on&nbsp;which&nbsp;translation&nbsp;files&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;will&nbsp;be&nbsp;sought.&nbsp;Deprecated,&nbsp;prefer&nbsp;`(:resource-path&nbsp;*config*)`.&quot;
025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;will&nbsp;be&nbsp;sought.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
026&nbsp;&nbsp;&nbsp;&nbsp;&quot;i18n&quot;)
@ -89,7 +89,7 @@
028&nbsp;&nbsp;(def&nbsp;^:dynamic&nbsp;*default-language*
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
029&nbsp;&nbsp;&nbsp;&nbsp;&quot;The&nbsp;default&nbsp;language&nbsp;to&nbsp;seek.&nbsp;Deprecated,&nbsp;prefer&nbsp;`(:default-language&nbsp;*config*)`.&quot;
029&nbsp;&nbsp;&nbsp;&nbsp;&quot;The&nbsp;default&nbsp;language&nbsp;to&nbsp;seek.&quot;
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
030&nbsp;&nbsp;&nbsp;&nbsp;(-&gt;&nbsp;(locale&#x2F;get-default)&nbsp;locale&#x2F;to-language-tag))
@ -97,617 +97,560 @@
<span class="blank" title="0 out of 0 forms covered">
031&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
032&nbsp;&nbsp;(def&nbsp;^:dynamic&nbsp;*config*
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
033&nbsp;&nbsp;&nbsp;&nbsp;&quot;Extensible&nbsp;configuration&nbsp;for&nbsp;i18n.&quot;
</span><br/>
<span class="covered" title="8 out of 8 forms covered">
034&nbsp;&nbsp;&nbsp;&nbsp;{:default-language&nbsp;(-&gt;&nbsp;(locale&#x2F;get-default)&nbsp;locale&#x2F;to-language-tag)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
035&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:resource-path&nbsp;&quot;i18n&quot;})
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
036&nbsp;&nbsp;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
037&nbsp;&nbsp;(def&nbsp;accept-language-grammar
032&nbsp;&nbsp;(def&nbsp;accept-language-grammar
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
038&nbsp;&nbsp;&nbsp;&nbsp;&quot;Grammar&nbsp;for&nbsp;`Accept-Language`&nbsp;headers&quot;
033&nbsp;&nbsp;&nbsp;&nbsp;&quot;Grammar&nbsp;for&nbsp;`Accept-Language`&nbsp;headers&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
039&nbsp;&nbsp;&nbsp;&nbsp;&quot;HEADER&nbsp;:=&nbsp;SPECIFIER&nbsp;|&nbsp;SPECIFIERS;
034&nbsp;&nbsp;&nbsp;&nbsp;&quot;HEADER&nbsp;:=&nbsp;SPECIFIER&nbsp;|&nbsp;SPECIFIERS;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
040&nbsp;&nbsp;&nbsp;&nbsp;SPECIFIERS:=&nbsp;SPECIFIER&nbsp;|&nbsp;SPECIFIER&nbsp;SPEC-SEP&nbsp;SPECIFIERS;
035&nbsp;&nbsp;&nbsp;&nbsp;SPECIFIERS:=&nbsp;SPECIFIER&nbsp;|&nbsp;SPECIFIER&nbsp;SPEC-SEP&nbsp;SPECIFIERS;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
041&nbsp;&nbsp;&nbsp;&nbsp;SPEC-SEP&nbsp;:=&nbsp;#&#x27;,\\s*&#x27;;
036&nbsp;&nbsp;&nbsp;&nbsp;SPEC-SEP&nbsp;:=&nbsp;#&#x27;,\\s*&#x27;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
042&nbsp;&nbsp;&nbsp;&nbsp;SPECIFIER&nbsp;:=&nbsp;LANGUAGE-TAG&nbsp;|&nbsp;LANGUAGE-TAG&nbsp;Q-SEP&nbsp;Q-VALUE;
037&nbsp;&nbsp;&nbsp;&nbsp;SPECIFIER&nbsp;:=&nbsp;LANGUAGE-TAG&nbsp;|&nbsp;LANGUAGE-TAG&nbsp;Q-SEP&nbsp;Q-VALUE;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
043&nbsp;&nbsp;&nbsp;&nbsp;LANGUAGE-TAG&nbsp;:=&nbsp;PRIMARY-TAG&nbsp;|&nbsp;PRIMARY-TAG&nbsp;&#x27;-&#x27;&nbsp;SUB-TAGS;
038&nbsp;&nbsp;&nbsp;&nbsp;LANGUAGE-TAG&nbsp;:=&nbsp;PRIMARY-TAG&nbsp;|&nbsp;PRIMARY-TAG&nbsp;&#x27;-&#x27;&nbsp;SUB-TAGS;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
044&nbsp;&nbsp;&nbsp;&nbsp;PRIMARY-TAG&nbsp;:=&nbsp;#&#x27;[a-zA-Z]+&#x27;;
039&nbsp;&nbsp;&nbsp;&nbsp;PRIMARY-TAG&nbsp;:=&nbsp;#&#x27;[a-zA-Z]+&#x27;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
045&nbsp;&nbsp;&nbsp;&nbsp;SUB-TAGS&nbsp;:=&nbsp;SUB-TAG&nbsp;|&nbsp;SUB-TAG&nbsp;&#x27;-&#x27;&nbsp;SUB-TAGS;
040&nbsp;&nbsp;&nbsp;&nbsp;SUB-TAGS&nbsp;:=&nbsp;SUB-TAG&nbsp;|&nbsp;SUB-TAG&nbsp;&#x27;-&#x27;&nbsp;SUB-TAGS;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
046&nbsp;&nbsp;&nbsp;&nbsp;SUB-TAG&nbsp;:=&nbsp;#&#x27;[a-zA-Z0-9]+&#x27;;
041&nbsp;&nbsp;&nbsp;&nbsp;SUB-TAG&nbsp;:=&nbsp;#&#x27;[a-zA-Z0-9]+&#x27;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
047&nbsp;&nbsp;&nbsp;&nbsp;Q-SEP&nbsp;:=&nbsp;#&#x27;;\\s*q=&#x27;
042&nbsp;&nbsp;&nbsp;&nbsp;Q-SEP&nbsp;:=&nbsp;#&#x27;;\\s*q=&#x27;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
048&nbsp;&nbsp;&nbsp;&nbsp;Q-VALUE&nbsp;:=&nbsp;&#x27;1&#x27;&nbsp;|&nbsp;#&#x27;0.[0-9]+&#x27;;&quot;)
043&nbsp;&nbsp;&nbsp;&nbsp;Q-VALUE&nbsp;:=&nbsp;&#x27;1&#x27;&nbsp;|&nbsp;#&#x27;0.[0-9]+&#x27;;&quot;)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
049&nbsp;&nbsp;
044&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
050&nbsp;&nbsp;(def&nbsp;parse-accept-language-header
045&nbsp;&nbsp;(def&nbsp;parse-accept-language-header
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
051&nbsp;&nbsp;&nbsp;&nbsp;&quot;Parse&nbsp;an&nbsp;`Accept-Language`&nbsp;header&quot;
046&nbsp;&nbsp;&nbsp;&nbsp;&quot;Parse&nbsp;an&nbsp;`Accept-Language`&nbsp;header&quot;
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
052&nbsp;&nbsp;&nbsp;&nbsp;(insta&#x2F;parser&nbsp;accept-language-grammar))
047&nbsp;&nbsp;&nbsp;&nbsp;(insta&#x2F;parser&nbsp;accept-language-grammar))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
053&nbsp;&nbsp;
048&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
054&nbsp;&nbsp;(defn&nbsp;generate-accept-languages
049&nbsp;&nbsp;(defn&nbsp;generate-accept-languages
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
055&nbsp;&nbsp;&nbsp;&nbsp;&quot;From&nbsp;a&nbsp;`parse-tree`&nbsp;generated&nbsp;by&nbsp;the&nbsp;`language-specifier-grammar`,&nbsp;generate
050&nbsp;&nbsp;&nbsp;&nbsp;&quot;From&nbsp;a&nbsp;`parse-tree`&nbsp;generated&nbsp;by&nbsp;the&nbsp;`language-specifier-grammar`,&nbsp;generate
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
056&nbsp;&nbsp;&nbsp;&nbsp;a&nbsp;list&nbsp;of&nbsp;maps&nbsp;each&nbsp;having&nbsp;a&nbsp;`:language`&nbsp;key,&nbsp;a&nbsp;`:preference`&nbsp;key&nbsp;and&nbsp;a
051&nbsp;&nbsp;&nbsp;&nbsp;a&nbsp;list&nbsp;of&nbsp;maps&nbsp;each&nbsp;having&nbsp;a&nbsp;`:language`&nbsp;key,&nbsp;a&nbsp;`:preference`&nbsp;key&nbsp;and&nbsp;a
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
057&nbsp;&nbsp;&nbsp;&nbsp;`:qualifier`&nbsp;key.&quot;
052&nbsp;&nbsp;&nbsp;&nbsp;`:qualifier`&nbsp;key.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
058&nbsp;&nbsp;&nbsp;&nbsp;{:doc&#x2F;format&nbsp;:markdown}
053&nbsp;&nbsp;&nbsp;&nbsp;{:doc&#x2F;format&nbsp;:markdown}
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
059&nbsp;&nbsp;&nbsp;&nbsp;[parse-tree]
054&nbsp;&nbsp;&nbsp;&nbsp;[parse-tree]
</span><br/>
<span class="partial" title="1 out of 2 forms covered">
060&nbsp;&nbsp;&nbsp;&nbsp;(if
055&nbsp;&nbsp;&nbsp;&nbsp;(if
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
061&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(nil?&nbsp;parse-tree)
056&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(nil?&nbsp;parse-tree)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
062&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil
057&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil
</span><br/>
<span class="partial" title="2 out of 4 forms covered">
063&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(case
058&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(case
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
064&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(first&nbsp;parse-tree)
059&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(first&nbsp;parse-tree)
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
065&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:HEADER&nbsp;(generate-accept-languages&nbsp;(second&nbsp;parse-tree))
060&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:HEADER&nbsp;(generate-accept-languages&nbsp;(second&nbsp;parse-tree))
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
066&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:SPECIFIERS&nbsp;(cons
061&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:SPECIFIERS&nbsp;(cons
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
067&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(generate-accept-languages&nbsp;(second&nbsp;parse-tree))
062&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(generate-accept-languages&nbsp;(second&nbsp;parse-tree))
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
068&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(when&nbsp;(&gt;=&nbsp;(count&nbsp;parse-tree)&nbsp;3)
063&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(when&nbsp;(&gt;=&nbsp;(count&nbsp;parse-tree)&nbsp;3)
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
069&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(generate-accept-languages&nbsp;(nth&nbsp;parse-tree&nbsp;3))))
064&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(generate-accept-languages&nbsp;(nth&nbsp;parse-tree&nbsp;3))))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
070&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:SPEC-SEP&nbsp;nil
065&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:SPEC-SEP&nbsp;nil
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
071&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:SPECIFIER&nbsp;(assoc
066&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:SPECIFIER&nbsp;(assoc
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
072&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(generate-accept-languages&nbsp;(second&nbsp;parse-tree))
067&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(generate-accept-languages&nbsp;(second&nbsp;parse-tree))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
073&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:preference
068&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:preference
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
074&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if
069&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
075&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;=&nbsp;(count&nbsp;parse-tree)&nbsp;3)
070&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;=&nbsp;(count&nbsp;parse-tree)&nbsp;3)
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
076&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(generate-accept-languages&nbsp;(nth&nbsp;parse-tree&nbsp;3))
071&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(generate-accept-languages&nbsp;(nth&nbsp;parse-tree&nbsp;3))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
077&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1))
072&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1))
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
078&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:LANGUAGE-TAG&nbsp;(if
073&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:LANGUAGE-TAG&nbsp;(if
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
079&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;=&nbsp;(count&nbsp;parse-tree)&nbsp;3)
074&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;=&nbsp;(count&nbsp;parse-tree)&nbsp;3)
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
080&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc
075&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
081&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(generate-accept-languages&nbsp;(second&nbsp;parse-tree))
076&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(generate-accept-languages&nbsp;(second&nbsp;parse-tree))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
082&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:qualifier
077&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:qualifier
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
083&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(generate-accept-languages&nbsp;(nth&nbsp;parse-tree&nbsp;3)))
078&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(generate-accept-languages&nbsp;(nth&nbsp;parse-tree&nbsp;3)))
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
084&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(generate-accept-languages&nbsp;(second&nbsp;parse-tree)))
079&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(generate-accept-languages&nbsp;(second&nbsp;parse-tree)))
</span><br/>
<span class="covered" title="7 out of 7 forms covered">
085&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:PRIMARY-TAG&nbsp;{:language&nbsp;(second&nbsp;parse-tree)&nbsp;:qualifier&nbsp;&quot;*&quot;}
080&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:PRIMARY-TAG&nbsp;{:language&nbsp;(second&nbsp;parse-tree)&nbsp;:qualifier&nbsp;&quot;*&quot;}
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
086&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:SUB-TAGS&nbsp;(if
081&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:SUB-TAGS&nbsp;(if
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
087&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;=&nbsp;(count&nbsp;parse-tree)&nbsp;3)
082&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;=&nbsp;(count&nbsp;parse-tree)&nbsp;3)
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
088&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str
083&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
089&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(generate-accept-languages&nbsp;(second&nbsp;parse-tree))
084&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(generate-accept-languages&nbsp;(second&nbsp;parse-tree))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
090&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;-&quot;
085&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;-&quot;
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
091&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(generate-accept-languages&nbsp;(nth&nbsp;parse-tree&nbsp;3)))
086&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(generate-accept-languages&nbsp;(nth&nbsp;parse-tree&nbsp;3)))
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
092&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(generate-accept-languages&nbsp;(second&nbsp;parse-tree)))
087&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(generate-accept-languages&nbsp;(second&nbsp;parse-tree)))
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
093&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:SUB-TAG&nbsp;(second&nbsp;parse-tree)
088&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:SUB-TAG&nbsp;(second&nbsp;parse-tree)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
094&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:Q-SEP&nbsp;nil
089&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:Q-SEP&nbsp;nil
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
095&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:Q-VALUE&nbsp;(read-string&nbsp;(second&nbsp;parse-tree))
090&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:Q-VALUE&nbsp;(read-string&nbsp;(second&nbsp;parse-tree))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
096&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;default
091&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;default
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
097&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(do
092&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(do
</span><br/>
<span class="not-covered" title="0 out of 16 forms covered">
098&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(timbre&#x2F;error&nbsp;&quot;Unable&nbsp;to&nbsp;parse&nbsp;header.&quot;)
093&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(timbre&#x2F;error&nbsp;&quot;Unable&nbsp;to&nbsp;parse&nbsp;header.&quot;)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
099&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil))))
094&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
095&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
096&nbsp;&nbsp;(defn&nbsp;acceptable-languages
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
097&nbsp;&nbsp;&nbsp;&nbsp;&quot;Generate&nbsp;an&nbsp;ordered&nbsp;list&nbsp;of&nbsp;acceptable&nbsp;languages,&nbsp;most-preferred&nbsp;first.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
098&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
099&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`accept-language-header`&nbsp;should&nbsp;be&nbsp;the&nbsp;value&nbsp;of&nbsp;an&nbsp;RFC2616&nbsp;`Accept-Language`&nbsp;header.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
100&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
101&nbsp;&nbsp;(defn&nbsp;acceptable-languages
<span class="not-tracked" title="0 out of 0 forms covered">
101&nbsp;&nbsp;&nbsp;&nbsp;Returns&nbsp;a&nbsp;list&nbsp;of&nbsp;maps&nbsp;as&nbsp;generated&nbsp;by&nbsp;`generate-accept-languages`,&nbsp;in&nbsp;descending&nbsp;order
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
102&nbsp;&nbsp;&nbsp;&nbsp;&quot;Generate&nbsp;an&nbsp;ordered&nbsp;list&nbsp;of&nbsp;acceptable&nbsp;languages,&nbsp;most-preferred&nbsp;first.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
103&nbsp;&nbsp;
102&nbsp;&nbsp;&nbsp;&nbsp;of&nbsp;preference.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
104&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`accept-language-header`&nbsp;should&nbsp;be&nbsp;the&nbsp;value&nbsp;of&nbsp;an&nbsp;RFC2616&nbsp;`Accept-Language`&nbsp;header.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
105&nbsp;&nbsp;
103&nbsp;&nbsp;&nbsp;&nbsp;{:doc&#x2F;format&nbsp;:markdown}
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
106&nbsp;&nbsp;&nbsp;&nbsp;Returns&nbsp;a&nbsp;list&nbsp;of&nbsp;maps&nbsp;as&nbsp;generated&nbsp;by&nbsp;`generate-accept-languages`,&nbsp;in&nbsp;descending&nbsp;order
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
107&nbsp;&nbsp;&nbsp;&nbsp;of&nbsp;preference.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
108&nbsp;&nbsp;&nbsp;&nbsp;{:doc&#x2F;format&nbsp;:markdown}
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
109&nbsp;&nbsp;&nbsp;&nbsp;[accept-language-header]
104&nbsp;&nbsp;&nbsp;&nbsp;[accept-language-header]
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
110&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[parse-tree&nbsp;(parse-accept-language-header&nbsp;accept-language-header)]
105&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[parse-tree&nbsp;(parse-accept-language-header&nbsp;accept-language-header)]
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
111&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(vector?&nbsp;parse-tree)
106&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(vector?&nbsp;parse-tree)
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
112&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(reverse
107&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(reverse
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
113&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(sort-by
108&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(sort-by
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
114&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:preference
109&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:preference
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
115&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(generate-accept-languages
110&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(generate-accept-languages
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
116&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parse-tree)))
111&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parse-tree)))
</span><br/>
<span class="not-covered" title="0 out of 21 forms covered">
117&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(timbre&#x2F;error&nbsp;&quot;Failed&nbsp;to&nbsp;parse&nbsp;Accept-Language&nbsp;header&nbsp;&#x27;&quot;&nbsp;accept-language-header&nbsp;&quot;&#x27;:\n&quot;&nbsp;(str&nbsp;parse-tree)))))
<span class="covered" title="21 out of 21 forms covered">
112&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(timbre&#x2F;error&nbsp;&quot;Failed&nbsp;to&nbsp;parse&nbsp;Accept-Language&nbsp;header&nbsp;&#x27;&quot;&nbsp;accept-language-header&nbsp;&quot;&#x27;:\n&quot;&nbsp;(str&nbsp;parse-tree)))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
118&nbsp;&nbsp;
113&nbsp;&nbsp;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
119&nbsp;&nbsp;
114&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
120&nbsp;&nbsp;(defn&nbsp;slurp-resource
115&nbsp;&nbsp;(defn&nbsp;slurp-resource
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
121&nbsp;&nbsp;&nbsp;&nbsp;&quot;Slurp&nbsp;the&nbsp;resource&nbsp;of&nbsp;this&nbsp;name&nbsp;and&nbsp;return&nbsp;its&nbsp;contents&nbsp;as&nbsp;a&nbsp;string;&nbsp;but&nbsp;if&nbsp;it&nbsp;doesn&#x27;t
116&nbsp;&nbsp;&nbsp;&nbsp;&quot;Slurp&nbsp;the&nbsp;resource&nbsp;of&nbsp;this&nbsp;name&nbsp;and&nbsp;return&nbsp;its&nbsp;contents&nbsp;as&nbsp;a&nbsp;string;&nbsp;but&nbsp;if&nbsp;it&nbsp;doesn&#x27;t
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
122&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exist&nbsp;log&nbsp;the&nbsp;fact&nbsp;and&nbsp;return&nbsp;nil,&nbsp;rather&nbsp;than&nbsp;throwing&nbsp;an&nbsp;exception.&quot;
117&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exist&nbsp;log&nbsp;the&nbsp;fact&nbsp;and&nbsp;return&nbsp;nil,&nbsp;rather&nbsp;than&nbsp;throwing&nbsp;an&nbsp;exception.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
123&nbsp;&nbsp;&nbsp;&nbsp;[name]
118&nbsp;&nbsp;&nbsp;&nbsp;[name]
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
124&nbsp;&nbsp;&nbsp;&nbsp;(try
119&nbsp;&nbsp;&nbsp;&nbsp;(try
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
125&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(slurp&nbsp;(io&#x2F;resource&nbsp;name))
120&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(slurp&nbsp;(io&#x2F;resource&nbsp;name))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
126&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(catch&nbsp;Exception&nbsp;_
121&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(catch&nbsp;Exception&nbsp;_
</span><br/>
<span class="covered" title="20 out of 20 forms covered">
127&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(timbre&#x2F;warn&nbsp;(str&nbsp;&quot;Resource&nbsp;at&nbsp;&quot;&nbsp;name&nbsp;&quot;&nbsp;does&nbsp;not&nbsp;exist.&quot;))
122&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(timbre&#x2F;error&nbsp;(str&nbsp;&quot;Resource&nbsp;at&nbsp;&quot;&nbsp;name&nbsp;&quot;&nbsp;does&nbsp;not&nbsp;exist.&quot;))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
128&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil)))
123&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
129&nbsp;&nbsp;
124&nbsp;&nbsp;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
130&nbsp;&nbsp;
125&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
131&nbsp;&nbsp;(defn&nbsp;find-language-file-name
126&nbsp;&nbsp;(defn&nbsp;find-language-file-name
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
132&nbsp;&nbsp;&nbsp;&nbsp;&quot;Find&nbsp;the&nbsp;name&nbsp;of&nbsp;a&nbsp;messages&nbsp;file&nbsp;on&nbsp;this&nbsp;resource&nbsp;path&nbsp;which&nbsp;matches&nbsp;this&nbsp;`language-spec`.
127&nbsp;&nbsp;&nbsp;&nbsp;&quot;Find&nbsp;the&nbsp;name&nbsp;of&nbsp;a&nbsp;messages&nbsp;file&nbsp;on&nbsp;this&nbsp;resource&nbsp;path&nbsp;which&nbsp;matches&nbsp;this&nbsp;`language-spec`.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
128&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
129&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`language-spec`&nbsp;should&nbsp;be&nbsp;either&nbsp;a&nbsp;map&nbsp;as&nbsp;generated&nbsp;by&nbsp;`generate-accept-languages`,&nbsp;or
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
130&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;a&nbsp;string;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
131&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`resource-path`&nbsp;should&nbsp;be&nbsp;the&nbsp;path&nbsp;name&nbsp;of&nbsp;the&nbsp;directory&nbsp;in&nbsp;which&nbsp;message&nbsp;files&nbsp;are&nbsp;stored,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
132&nbsp;&nbsp;&nbsp;&nbsp;within&nbsp;the&nbsp;resources&nbsp;on&nbsp;the&nbsp;classpath.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
133&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
134&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`language-spec`&nbsp;should&nbsp;be&nbsp;either&nbsp;a&nbsp;map&nbsp;as&nbsp;generated&nbsp;by&nbsp;`generate-accept-languages`,&nbsp;or
134&nbsp;&nbsp;&nbsp;&nbsp;Returns&nbsp;the&nbsp;name&nbsp;of&nbsp;an&nbsp;appropriate&nbsp;file&nbsp;if&nbsp;any&nbsp;is&nbsp;found,&nbsp;else&nbsp;nil.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
135&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;a&nbsp;string;
135&nbsp;&nbsp;&nbsp;&nbsp;{:doc&#x2F;format&nbsp;:markdown}
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
136&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`resource-path`&nbsp;should&nbsp;be&nbsp;the&nbsp;path&nbsp;name&nbsp;of&nbsp;the&nbsp;directory&nbsp;in&nbsp;which&nbsp;message&nbsp;files&nbsp;are&nbsp;stored,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
137&nbsp;&nbsp;&nbsp;&nbsp;within&nbsp;the&nbsp;resources&nbsp;on&nbsp;the&nbsp;classpath.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
138&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
139&nbsp;&nbsp;&nbsp;&nbsp;Returns&nbsp;the&nbsp;name&nbsp;of&nbsp;an&nbsp;appropriate&nbsp;file&nbsp;if&nbsp;any&nbsp;is&nbsp;found,&nbsp;else&nbsp;nil.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
140&nbsp;&nbsp;&nbsp;&nbsp;{:doc&#x2F;format&nbsp;:markdown}
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
141&nbsp;&nbsp;&nbsp;&nbsp;[language-spec&nbsp;resource-path]
136&nbsp;&nbsp;&nbsp;&nbsp;[language-spec&nbsp;resource-path]
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
142&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[file-path&nbsp;(when
137&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[file-path&nbsp;(when
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
143&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(string?&nbsp;language-spec)
138&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(string?&nbsp;language-spec)
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
144&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(join
139&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(join
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
145&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;java.io.File&#x2F;separator
140&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;java.io.File&#x2F;separator
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
146&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[resource-path&nbsp;(str&nbsp;language-spec&nbsp;&quot;.edn&quot;)]))
141&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[resource-path&nbsp;(str&nbsp;language-spec&nbsp;&quot;.edn&quot;)]))
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
147&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents&nbsp;(when&nbsp;file-path&nbsp;(slurp-resource&nbsp;file-path))]
142&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents&nbsp;(when&nbsp;file-path&nbsp;(slurp-resource&nbsp;file-path))]
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
148&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond
143&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
149&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents
144&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
150&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;file-path
145&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;file-path
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
151&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map?&nbsp;language-spec)
146&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map?&nbsp;language-spec)
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
152&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or
147&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
153&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(find-language-file-name
148&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(find-language-file-name
</span><br/>
<span class="covered" title="9 out of 9 forms covered">
154&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str&nbsp;(:language&nbsp;language-spec)&nbsp;&quot;-&quot;&nbsp;(:qualifier&nbsp;language-spec))
149&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str&nbsp;(:language&nbsp;language-spec)&nbsp;&quot;-&quot;&nbsp;(:qualifier&nbsp;language-spec))
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
155&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resource-path)
150&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resource-path)
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
156&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(find-language-file-name
151&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(find-language-file-name
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
157&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:language&nbsp;language-spec)
152&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:language&nbsp;language-spec)
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
158&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resource-path)))))
153&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resource-path)))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
159&nbsp;&nbsp;
154&nbsp;&nbsp;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
155&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
156&nbsp;&nbsp;(defn&nbsp;raw-get-messages
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
157&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;the&nbsp;most&nbsp;acceptable&nbsp;messages&nbsp;collection&nbsp;we&nbsp;have&nbsp;given&nbsp;this&nbsp;`accept-language-header`.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
158&nbsp;&nbsp;&nbsp;&nbsp;Do&nbsp;not&nbsp;use&nbsp;this&nbsp;function&nbsp;directly,&nbsp;use&nbsp;the&nbsp;memoized&nbsp;variant&nbsp;`get-messages`,&nbsp;as&nbsp;performance
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
159&nbsp;&nbsp;&nbsp;&nbsp;will&nbsp;be&nbsp;very&nbsp;much&nbsp;better.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
160&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
161&nbsp;&nbsp;(defn&nbsp;raw-get-messages
<span class="not-tracked" title="0 out of 0 forms covered">
161&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`accept-language-header`&nbsp;should&nbsp;be&nbsp;the&nbsp;value&nbsp;of&nbsp;an&nbsp;RFC2616&nbsp;`Accept-Language`&nbsp;header;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
162&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;the&nbsp;most&nbsp;acceptable&nbsp;messages&nbsp;collection&nbsp;we&nbsp;have&nbsp;given&nbsp;this&nbsp;`accept-language-header`.
162&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`resource-path`&nbsp;should&nbsp;be&nbsp;the&nbsp;fully-qualified&nbsp;path&nbsp;name&nbsp;of&nbsp;the&nbsp;directory&nbsp;in&nbsp;which
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
163&nbsp;&nbsp;&nbsp;&nbsp;Do&nbsp;not&nbsp;use&nbsp;this&nbsp;function&nbsp;directly,&nbsp;use&nbsp;the&nbsp;memoized&nbsp;variant&nbsp;`get-messages`,&nbsp;as&nbsp;performance
163&nbsp;&nbsp;&nbsp;&nbsp;message&nbsp;files&nbsp;are&nbsp;stored;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
164&nbsp;&nbsp;&nbsp;&nbsp;will&nbsp;be&nbsp;very&nbsp;much&nbsp;better.
164&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`default-locale`&nbsp;should&nbsp;be&nbsp;a&nbsp;locale&nbsp;specifier&nbsp;to&nbsp;use&nbsp;if&nbsp;no&nbsp;acceptable&nbsp;locale&nbsp;can&nbsp;be
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
165&nbsp;&nbsp;&nbsp;&nbsp;identified.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
165&nbsp;&nbsp;
166&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
166&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`accept-language-header`&nbsp;should&nbsp;be&nbsp;the&nbsp;value&nbsp;of&nbsp;an&nbsp;RFC2616&nbsp;`Accept-Language`&nbsp;header;
167&nbsp;&nbsp;&nbsp;&nbsp;Returns&nbsp;a&nbsp;map&nbsp;of&nbsp;message&nbsp;keys&nbsp;to&nbsp;strings;&nbsp;if&nbsp;no&nbsp;useable&nbsp;file&nbsp;is&nbsp;found,&nbsp;returns&nbsp;nil.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
167&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`resource-path`&nbsp;should&nbsp;be&nbsp;the&nbsp;fully-qualified&nbsp;path&nbsp;name&nbsp;of&nbsp;the&nbsp;directory&nbsp;in&nbsp;which
168&nbsp;&nbsp;&nbsp;&nbsp;{:doc&#x2F;format&nbsp;:markdown}
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
168&nbsp;&nbsp;&nbsp;&nbsp;message&nbsp;files&nbsp;are&nbsp;stored;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
169&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`default-locale`&nbsp;should&nbsp;be&nbsp;a&nbsp;locale&nbsp;specifier&nbsp;to&nbsp;use&nbsp;if&nbsp;no&nbsp;acceptable&nbsp;locale&nbsp;can&nbsp;be
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
170&nbsp;&nbsp;&nbsp;&nbsp;identified.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
171&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
172&nbsp;&nbsp;&nbsp;&nbsp;Returns&nbsp;a&nbsp;map&nbsp;of&nbsp;message&nbsp;keys&nbsp;to&nbsp;strings;&nbsp;if&nbsp;no&nbsp;useable&nbsp;file&nbsp;is&nbsp;found,&nbsp;returns&nbsp;nil.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
173&nbsp;&nbsp;&nbsp;&nbsp;{:doc&#x2F;format&nbsp;:markdown}
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
174&nbsp;&nbsp;&nbsp;&nbsp;[^String&nbsp;accept-language-header&nbsp;^String&nbsp;resource-path&nbsp;^String&nbsp;default-locale]
169&nbsp;&nbsp;&nbsp;&nbsp;[^String&nbsp;accept-language-header&nbsp;^String&nbsp;resource-path&nbsp;^String&nbsp;default-locale]
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
175&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[file-paths&nbsp;(remove
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
176&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;empty?
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
177&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
178&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(find-language-file-name&nbsp;%&nbsp;resource-path)
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
179&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(acceptable-languages&nbsp;accept-language-header)))
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
180&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default-path&nbsp;(join&nbsp;java.io.File&#x2F;separator
170&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[file-path&nbsp;(first
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
181&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[resource-path
171&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(remove
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
172&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil?
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
173&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
182&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str&nbsp;default-locale&nbsp;&quot;.edn&quot;)])
174&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(find-language-file-name&nbsp;%&nbsp;resource-path)
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
175&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(acceptable-languages&nbsp;accept-language-header))))]
</span><br/>
<span class="covered" title="20 out of 20 forms covered">
176&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(timbre&#x2F;debug&nbsp;(str&nbsp;&quot;Found&nbsp;i18n&nbsp;file&nbsp;at&nbsp;&#x27;&quot;&nbsp;file-path&nbsp;&quot;&#x27;&quot;))
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
177&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(try
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
178&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(read-string
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
179&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(slurp-resource
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
180&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
181&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;file-path
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
182&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(join&nbsp;java.io.File&#x2F;separator
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
183&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[resource-path
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
184&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str&nbsp;default-locale&nbsp;&quot;.edn&quot;)]))))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
185&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(catch&nbsp;Exception&nbsp;any
</span><br/>
<span class="covered" title="19 out of 19 forms covered">
186&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(timbre&#x2F;error&nbsp;(str&nbsp;&quot;Failed&nbsp;to&nbsp;load&nbsp;internationalisation&nbsp;because&nbsp;&quot;&nbsp;(.getMessage&nbsp;any)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
187&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
188&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
189&nbsp;&nbsp;(def&nbsp;get-messages
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
190&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;the&nbsp;most&nbsp;acceptable&nbsp;messages&nbsp;collection&nbsp;we&nbsp;have&nbsp;given&nbsp;this&nbsp;`accept-language-header`
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
191&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
192&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`accept-language-header`&nbsp;should&nbsp;be&nbsp;the&nbsp;value&nbsp;of&nbsp;an&nbsp;RFC2616&nbsp;`Accept-Language`&nbsp;header;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
193&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`resource-path`&nbsp;should&nbsp;be&nbsp;the&nbsp;fully-qualified&nbsp;path&nbsp;name&nbsp;of&nbsp;the&nbsp;directory&nbsp;in&nbsp;which
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
194&nbsp;&nbsp;&nbsp;&nbsp;message&nbsp;files&nbsp;are&nbsp;stored;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
195&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`default-locale`&nbsp;should&nbsp;be&nbsp;a&nbsp;locale&nbsp;specifier&nbsp;to&nbsp;use&nbsp;if&nbsp;no&nbsp;acceptable&nbsp;locale&nbsp;can&nbsp;be
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
196&nbsp;&nbsp;&nbsp;&nbsp;identified.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
197&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
198&nbsp;&nbsp;&nbsp;&nbsp;Returns&nbsp;a&nbsp;map&nbsp;of&nbsp;message&nbsp;keys&nbsp;to&nbsp;strings.;&nbsp;if&nbsp;no&nbsp;useable&nbsp;file&nbsp;is&nbsp;found,&nbsp;returns&nbsp;nil.&quot;
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
199&nbsp;&nbsp;&nbsp;&nbsp;(memoize&nbsp;raw-get-messages))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
200&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
201&nbsp;&nbsp;(def&nbsp;get-message
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
202&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;the&nbsp;message&nbsp;keyed&nbsp;by&nbsp;this&nbsp;`token`&nbsp;from&nbsp;the&nbsp;most&nbsp;acceptable&nbsp;messages&nbsp;collection&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
203&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;we&nbsp;have&nbsp;given&nbsp;this&nbsp;`accept-language-header`.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
204&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
205&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`token`&nbsp;should&nbsp;be&nbsp;a&nbsp;clojure&nbsp;keyword&nbsp;identifying&nbsp;the&nbsp;message&nbsp;to&nbsp;be&nbsp;retrieved;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
206&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`accept-language-header`&nbsp;should&nbsp;be&nbsp;the&nbsp;value&nbsp;of&nbsp;an&nbsp;RFC2616&nbsp;`Accept-Language`&nbsp;header;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
207&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`resource-path`&nbsp;should&nbsp;be&nbsp;the&nbsp;fully-qualified&nbsp;path&nbsp;name&nbsp;of&nbsp;the&nbsp;directory&nbsp;in&nbsp;which
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
208&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message&nbsp;files&nbsp;are&nbsp;stored;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
209&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`default-locale`&nbsp;should&nbsp;be&nbsp;a&nbsp;locale&nbsp;specifier&nbsp;to&nbsp;use&nbsp;if&nbsp;no&nbsp;acceptable&nbsp;locale&nbsp;can&nbsp;be
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
210&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;identified.&quot;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
211&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;([^Keyword&nbsp;token&nbsp;^String&nbsp;accept-language-header&nbsp;^String&nbsp;resource-path&nbsp;^String&nbsp;default-locale]
</span><br/>
<span class="covered" title="7 out of 7 forms covered">
212&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;((get-messages&nbsp;accept-language-header&nbsp;resource-path&nbsp;default-locale)&nbsp;token))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
213&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;([^Keyword&nbsp;token&nbsp;^String&nbsp;accept-language-header]
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
183&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;paths&nbsp;(concat&nbsp;file-paths&nbsp;(list&nbsp;default-path))
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
184&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;text&nbsp;(first&nbsp;
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
185&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(remove&nbsp;empty?
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
186&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
187&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;slurp-resource
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
188&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;paths)))]
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
189&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;text
</span><br/>
<span class="partial" title="1 out of 2 forms covered">
190&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(try
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
191&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(read-string&nbsp;text)
214&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(get-message&nbsp;token&nbsp;accept-language-header&nbsp;*resource-path*&nbsp;*default-language*))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
192&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(catch&nbsp;Exception&nbsp;any
215&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;([^Keyword&nbsp;token]
</span><br/>
<span class="not-covered" title="0 out of 16 forms covered">
193&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(timbre&#x2F;error&nbsp;&nbsp;&quot;Failed&nbsp;to&nbsp;load&nbsp;internationalisation&nbsp;because&nbsp;&quot;
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
194&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(.getName&nbsp;(.getClass&nbsp;any))
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
195&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(.getMessage&nbsp;any))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
196&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
197&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;else
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
198&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(doall
</span><br/>
<span class="covered" title="17 out of 17 forms covered">
199&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(timbre&#x2F;error&nbsp;&quot;No&nbsp;valid&nbsp;i18n&nbsp;files&nbsp;found,&nbsp;not&nbsp;even&nbsp;default.&nbsp;Tried&quot;&nbsp;paths)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
200&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
201&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
202&nbsp;&nbsp;(def&nbsp;get-messages
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
203&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;the&nbsp;most&nbsp;acceptable&nbsp;messages&nbsp;collection&nbsp;we&nbsp;have&nbsp;given&nbsp;this&nbsp;`accept-language-header`
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
204&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
205&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`accept-language-header`&nbsp;should&nbsp;be&nbsp;the&nbsp;value&nbsp;of&nbsp;an&nbsp;RFC2616&nbsp;`Accept-Language`&nbsp;header;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
206&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`resource-path`&nbsp;should&nbsp;be&nbsp;the&nbsp;fully-qualified&nbsp;path&nbsp;name&nbsp;of&nbsp;the&nbsp;directory&nbsp;in&nbsp;which
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
207&nbsp;&nbsp;&nbsp;&nbsp;message&nbsp;files&nbsp;are&nbsp;stored;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
208&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`default-locale`&nbsp;should&nbsp;be&nbsp;a&nbsp;locale&nbsp;specifier&nbsp;to&nbsp;use&nbsp;if&nbsp;no&nbsp;acceptable&nbsp;locale&nbsp;can&nbsp;be
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
209&nbsp;&nbsp;&nbsp;&nbsp;identified.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
210&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
211&nbsp;&nbsp;&nbsp;&nbsp;Returns&nbsp;a&nbsp;map&nbsp;of&nbsp;message&nbsp;keys&nbsp;to&nbsp;strings.;&nbsp;if&nbsp;no&nbsp;useable&nbsp;file&nbsp;is&nbsp;found,&nbsp;returns&nbsp;nil.&quot;
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
212&nbsp;&nbsp;&nbsp;&nbsp;(memoize&nbsp;raw-get-messages))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
213&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
214&nbsp;&nbsp;(def&nbsp;get-message
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
215&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;the&nbsp;message&nbsp;keyed&nbsp;by&nbsp;this&nbsp;`token`&nbsp;from&nbsp;the&nbsp;most&nbsp;acceptable&nbsp;messages&nbsp;collection&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
216&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;we&nbsp;have&nbsp;given&nbsp;this&nbsp;`accept-language-header`,&nbsp;if&nbsp;passed,&nbsp;or&nbsp;the&nbsp;current&nbsp;default&nbsp;language&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
217&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;otherwise.&nbsp;If&nbsp;no&nbsp;message&nbsp;is&nbsp;found,&nbsp;return&nbsp;the&nbsp;token.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
218&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
219&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`token`&nbsp;should&nbsp;be&nbsp;a&nbsp;clojure&nbsp;keyword&nbsp;identifying&nbsp;the&nbsp;message&nbsp;to&nbsp;be&nbsp;retrieved;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
220&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`accept-language-header`&nbsp;should&nbsp;be&nbsp;the&nbsp;value&nbsp;of&nbsp;an&nbsp;RFC2616&nbsp;`Accept-Language`&nbsp;header;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
221&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`resource-path`&nbsp;should&nbsp;be&nbsp;the&nbsp;fully-qualified&nbsp;path&nbsp;name&nbsp;of&nbsp;the&nbsp;directory&nbsp;in&nbsp;which
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
222&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message&nbsp;files&nbsp;are&nbsp;stored;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
223&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`default-locale`&nbsp;should&nbsp;be&nbsp;a&nbsp;locale&nbsp;specifier&nbsp;to&nbsp;use&nbsp;if&nbsp;no&nbsp;acceptable&nbsp;locale&nbsp;can&nbsp;be
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
224&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;identified.&quot;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
225&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;([^Keyword&nbsp;token&nbsp;^String&nbsp;accept-language-header&nbsp;^String&nbsp;resource-path&nbsp;^String&nbsp;default-locale]
</span><br/>
<span class="covered" title="8 out of 8 forms covered">
226&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[message&nbsp;(token&nbsp;(get-messages&nbsp;accept-language-header&nbsp;resource-path&nbsp;default-locale))]
</span><br/>
<span class="covered" title="8 out of 8 forms covered">
227&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or&nbsp;message&nbsp;(name&nbsp;token))))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
228&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;([^Keyword&nbsp;token&nbsp;^String&nbsp;accept-language-header]
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
229&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(get-message&nbsp;token&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
230&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;accept-language-header&nbsp;
</span><br/>
<span class="covered" title="8 out of 8 forms covered">
231&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or&nbsp;(:resource-path&nbsp;*config*)&nbsp;*resource-path*)&nbsp;
</span><br/>
<span class="covered" title="8 out of 8 forms covered">
232&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or&nbsp;(:default-language&nbsp;*config*)&nbsp;*default-language*)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
233&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;([^Keyword&nbsp;token]
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
234&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(get-message&nbsp;token&nbsp;
</span><br/>
<span class="covered" title="8 out of 8 forms covered">
235&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or&nbsp;(:default-language&nbsp;*config*)&nbsp;*default-language*)))))
<span class="covered" title="6 out of 6 forms covered">
216&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(get-message&nbsp;token&nbsp;nil&nbsp;*resource-path*&nbsp;*default-language*))))
</span><br/>
</body>
</html>

View file

@ -1,3 +1,3 @@
<!DOCTYPE html PUBLIC ""
"">
<html><head><meta charset="UTF-8" /><title>Internationalisation 1.0.5</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Internationalisation</span> <span class="project-version">1.0.5</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1 current"><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1 "><a href="intro.html"><div class="inner"><span>internationalisation</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1 "><a href="scot.weft.i18n.core.html"><div class="inner"><span>scot.weft.i18n.core</span></div></a></li></ul></div><div class="namespace-index" id="content"><h1><span class="project-title"><span class="project-name">Internationalisation</span> <span class="project-version">1.0.5</span></span></h1><h5 class="license">Released under the <a href="http://www.eclipse.org/legal/epl-v10.html">Eclipse Public License</a></h5><div class="doc"><p>Internationalisation library for Clojure.</p></div><h2>Installation</h2><p>To install, add the following dependency to your project or build file:</p><pre class="deps">[org.clojars.simon_brooke/internationalisation "1.0.5"]</pre><h2>Topics</h2><ul class="topics"><li><a href="intro.html">internationalisation</a></li></ul><h2>Namespaces</h2><div class="namespace"><h3><a href="scot.weft.i18n.core.html">scot.weft.i18n.core</a></h3><div class="doc"><div class="markdown"><p>Internationalisation.</p></div></div><div class="index"><p>Public variables and functions:</p><ul><li> <a href="scot.weft.i18n.core.html#var-*config*">*config*</a> </li><li> <a href="scot.weft.i18n.core.html#var-*default-language*">*default-language*</a> </li><li> <a href="scot.weft.i18n.core.html#var-*resource-path*">*resource-path*</a> </li><li> <a href="scot.weft.i18n.core.html#var-accept-language-grammar">accept-language-grammar</a> </li><li> <a href="scot.weft.i18n.core.html#var-acceptable-languages">acceptable-languages</a> </li><li> <a href="scot.weft.i18n.core.html#var-find-language-file-name">find-language-file-name</a> </li><li> <a href="scot.weft.i18n.core.html#var-generate-accept-languages">generate-accept-languages</a> </li><li> <a href="scot.weft.i18n.core.html#var-get-message">get-message</a> </li><li> <a href="scot.weft.i18n.core.html#var-get-messages">get-messages</a> </li><li> <a href="scot.weft.i18n.core.html#var-parse-accept-language-header">parse-accept-language-header</a> </li><li> <a href="scot.weft.i18n.core.html#var-raw-get-messages">raw-get-messages</a> </li><li> <a href="scot.weft.i18n.core.html#var-slurp-resource">slurp-resource</a> </li></ul></div></div></div></body></html>
<html><head><meta charset="UTF-8" /><title>Internationalisation 1.0.3-SNAPSHOT</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Internationalisation</span> <span class="project-version">1.0.3-SNAPSHOT</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1 current"><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1 "><a href="intro.html"><div class="inner"><span>internationalisation</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1 "><a href="scot.weft.i18n.core.html"><div class="inner"><span>scot.weft.i18n.core</span></div></a></li></ul></div><div class="namespace-index" id="content"><h1><span class="project-title"><span class="project-name">Internationalisation</span> <span class="project-version">1.0.3-SNAPSHOT</span></span></h1><h5 class="license">Released under the <a href="http://www.eclipse.org/legal/epl-v10.html">Eclipse Public License</a></h5><div class="doc"><p>Internationalisation library for Clojure.</p></div><h2>Installation</h2><p>To install, add the following dependency to your project or build file:</p><pre class="deps">[org.clojars.simon_brooke/internationalisation "1.0.3-SNAPSHOT"]</pre><h2>Topics</h2><ul class="topics"><li><a href="intro.html">internationalisation</a></li></ul><h2>Namespaces</h2><div class="namespace"><h3><a href="scot.weft.i18n.core.html">scot.weft.i18n.core</a></h3><div class="doc"><div class="markdown"><p>Internationalisation.</p></div></div><div class="index"><p>Public variables and functions:</p><ul><li> <a href="scot.weft.i18n.core.html#var-*default-language*">*default-language*</a> </li><li> <a href="scot.weft.i18n.core.html#var-*resource-path*">*resource-path*</a> </li><li> <a href="scot.weft.i18n.core.html#var-accept-language-grammar">accept-language-grammar</a> </li><li> <a href="scot.weft.i18n.core.html#var-acceptable-languages">acceptable-languages</a> </li><li> <a href="scot.weft.i18n.core.html#var-find-language-file-name">find-language-file-name</a> </li><li> <a href="scot.weft.i18n.core.html#var-generate-accept-languages">generate-accept-languages</a> </li><li> <a href="scot.weft.i18n.core.html#var-get-message">get-message</a> </li><li> <a href="scot.weft.i18n.core.html#var-get-messages">get-messages</a> </li><li> <a href="scot.weft.i18n.core.html#var-parse-accept-language-header">parse-accept-language-header</a> </li><li> <a href="scot.weft.i18n.core.html#var-raw-get-messages">raw-get-messages</a> </li><li> <a href="scot.weft.i18n.core.html#var-slurp-resource">slurp-resource</a> </li></ul></div></div></div></body></html>

View file

@ -1,10 +1,10 @@
<!DOCTYPE html PUBLIC ""
"">
<html><head><meta charset="UTF-8" /><title>internationalisation</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Internationalisation</span> <span class="project-version">1.0.5</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1 "><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1 current"><a href="intro.html"><div class="inner"><span>internationalisation</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1 "><a href="scot.weft.i18n.core.html"><div class="inner"><span>scot.weft.i18n.core</span></div></a></li></ul></div><div class="document" id="content"><div class="doc"><div class="markdown"><h1><a href="#internationalisation" name="internationalisation"></a>internationalisation</h1>
<html><head><meta charset="UTF-8" /><title>internationalisation</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Internationalisation</span> <span class="project-version">1.0.3-SNAPSHOT</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1 "><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1 current"><a href="intro.html"><div class="inner"><span>internationalisation</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1 "><a href="scot.weft.i18n.core.html"><div class="inner"><span>scot.weft.i18n.core</span></div></a></li></ul></div><div class="document" id="content"><div class="doc"><div class="markdown"><h1><a href="#internationalisation" name="internationalisation"></a>internationalisation</h1>
<p>A Clojure library designed to provide simple interationalisation of user-facing messages.</p>
<h2><a href="#usage" name="usage"></a>Usage</h2>
<p>To use this library in your project, add the following leiningen dependency:</p>
<pre><code>[org.clojars.simon_brooke/internationalisation "1.0.5"]
<pre><code>[org.clojars.simon_brooke/internationalisation "1.0.4"]
</code></pre>
<p>To use it in your namespace, require:</p>
<pre><code>[scot.weft.i18n.core :refer [get-message get-messages]]
@ -45,15 +45,16 @@
(get-message :pipe "de-DE" "i18n" "ru")
</code></pre>
<p>So how does this work? When one calls <code>(get-message token accept-language-header)</code>, how does it know where to find resources? The answer is that there is a <code>*config*</code> map, with (currently) two significant keys:</p>
<p>So how does this work? When one calls <code>(get-message token accept-language-header)</code>, how does it know where to find resources? The answer is that there are two dynamic variables:</p>
<ul>
<li><code>:resource-path</code>, whose value should be a string representation of the default path within the resources space on which translation files will be sought. Initialised to <code>i18n</code>.</li>
<li><code>:default-language</code>, the language tag for the language to use when no otherwise suitable language can be identified. Initialised to the default language of the runtime session, so this may well be different on your machine from someone elses running identical software.</li>
<li><code>*resource-path*</code>, the default path within the resources space on which translation files will be sought. Initialised to <code>i18n</code>.</li>
<li><code>*default-language*</code>, the language tag for the language to use when no otherwise suitable language can be identified. Initialised to the default language of the runtime session, so this may well be different on your machine from someone elses running identical software.</li>
</ul>
<p>Thus</p>
<pre><code class="clojure">(binding [*config* {:resource-path "language-files"
:default-language "en-CA"}]
(get-message :pipe "en-GB;q=0.9, fr-FR"))
<pre><code class="clojure">(binding [*resource-path* "language-files"
*default-language* "en-CA"]
(get-message :pipe "en-GB;q=0.9, fr-FR")
)
</code></pre>
<p>and</p>
<pre><code class="clojure">(get-message :pipe "en-GB;q=0.9, fr-FR" "language-files" "en-CA")
@ -78,19 +79,9 @@
{:pipe "Ceci n'est pas une pipe."}
</code></pre>
<h2><a href="#documentation" name="documentation"></a>Documentation</h2>
<p>Documentation can be found here. It may be generated by running</p>
<p>Documentation may be generated by running</p>
<pre><code>lein codox
</code></pre>
<h2><a href="#future-direction" name="future-direction"></a>Future direction</h2>
<p>Its likely that in future configuration will be extended</p>
<ol>
<li>To read per-language keys/messages from CSV files;</li>
<li>To read per-language keys/messages from database tables;</li>
<li>potentially, to read per-language keys/messages from other sources.</li>
</ol>
<p>Pull requests implementing any of these things will be welcomed.</p>
<h2><a href="#deprecated-features" name="deprecated-features"></a>Deprecated features</h2>
<p>There are still two dynamic configuration variables, <code>*default-language*</code> and <code>*resource-path*</code>, but these are now superceded by the <code>*config*</code> map, which is extensible. Consequently, if you are using these configuration variables in production, you should bind <code>*config*</code> to <code>nil</code>.</p>
<h2><a href="#license" name="license"></a>License</h2>
<p>Copyright © 2017 Simon Brooke</p>
<p>Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.</p></div></div></div></body></html>

File diff suppressed because one or more lines are too long

View file

@ -1,4 +1,4 @@
(defproject org.clojars.simon_brooke/internationalisation "1.0.5"
(defproject org.clojars.simon_brooke/internationalisation "1.0.4"
:cloverage {:output "docs/cloverage"
:codecov? true
:emma-xml? true}

View file

@ -1,3 +1,3 @@
;;;; This is a British English translation file.
{:pipe "This is not a pipe."}
{:pipe "This is not a pipe"}

View file

@ -22,18 +22,13 @@
(def ^:dynamic *resource-path*
"The default path within the resources space on which translation files
will be sought. Deprecated, prefer `(:resource-path *config*)`."
will be sought."
"i18n")
(def ^:dynamic *default-language*
"The default language to seek. Deprecated, prefer `(:default-language *config*)`."
"The default language to seek."
(-> (locale/get-default) locale/to-language-tag))
(def ^:dynamic *config*
"Extensible configuration for i18n."
{:default-language (-> (locale/get-default) locale/to-language-tag)
:resource-path "i18n"})
(def accept-language-grammar
"Grammar for `Accept-Language` headers"
"HEADER := SPECIFIER | SPECIFIERS;
@ -124,7 +119,7 @@
(try
(slurp (io/resource name))
(catch Exception _
(timbre/warn (str "Resource at " name " does not exist."))
(timbre/error (str "Resource at " name " does not exist."))
nil)))
@ -172,31 +167,23 @@
Returns a map of message keys to strings; if no useable file is found, returns nil."
{:doc/format :markdown}
[^String accept-language-header ^String resource-path ^String default-locale]
(let [file-paths (remove
empty?
(let [file-path (first
(remove
nil?
(map
#(find-language-file-name % resource-path)
(acceptable-languages accept-language-header)))
default-path (join java.io.File/separator
(acceptable-languages accept-language-header))))]
(timbre/debug (str "Found i18n file at '" file-path "'"))
(try
(read-string
(slurp-resource
(or
file-path
(join java.io.File/separator
[resource-path
(str default-locale ".edn")])
paths (concat file-paths (list default-path))
text (first
(remove empty?
(map
slurp-resource
paths)))]
(if text
(try
(read-string text)
(catch Exception any
(timbre/error "Failed to load internationalisation because "
(.getName (.getClass any))
(.getMessage any))
nil))
;; else
(doall
(timbre/error "No valid i18n files found, not even default. Tried" paths)
(str default-locale ".edn")]))))
(catch Exception any
(timbre/error (str "Failed to load internationalisation because " (.getMessage any)))
nil))))
(def get-messages
@ -213,8 +200,7 @@
(def get-message
"Return the message keyed by this `token` from the most acceptable messages collection
we have given this `accept-language-header`, if passed, or the current default language
otherwise. If no message is found, return the token.
we have given this `accept-language-header`.
* `token` should be a clojure keyword identifying the message to be retrieved;
* `accept-language-header` should be the value of an RFC2616 `Accept-Language` header;
@ -223,13 +209,8 @@
* `default-locale` should be a locale specifier to use if no acceptable locale can be
identified."
(fn ([^Keyword token ^String accept-language-header ^String resource-path ^String default-locale]
(let [message (token (get-messages accept-language-header resource-path default-locale))]
(or message (name token))))
((get-messages accept-language-header resource-path default-locale) token))
([^Keyword token ^String accept-language-header]
(get-message token
accept-language-header
(or (:resource-path *config*) *resource-path*)
(or (:default-language *config*) *default-language*)))
(get-message token accept-language-header *resource-path* *default-language*))
([^Keyword token]
(get-message token
(or (:default-language *config*) *default-language*)))))
(get-message token nil *resource-path* *default-language*))))

View file

@ -1,8 +1,7 @@
(ns ^{:doc "Tests for Internationalisation."
:author "Simon Brooke"} scot.weft.i18n.test.core
(:require [clojure.test :refer [deftest is testing]]
[scot.weft.i18n.core :refer [*config*
*default-language*
[scot.weft.i18n.core :refer [*default-language*
acceptable-languages
generate-accept-languages
get-message
@ -207,7 +206,7 @@
(testing "Top level functionality"
(is
(=
"This is not a pipe."
"This is not a pipe"
(:pipe (get-messages "en-GB, fr-FR;q=0.9" "i18n" "en-GB"))))
(is
(=
@ -216,25 +215,9 @@
(is
(= nil (get-messages "xx-XX;q=0.5, yy-YY" "i18n" "zz-ZZ"))
"If no usable file is found, an exception should not be thrown.")
(binding [*config* (assoc *config* :default-language "fr-FR")]
(is (= "Ceci n'est pas une pipe." (get-message :pipe)))
(binding [*default-language* "en-GB"]
(is (= "This is not a pipe" (get-message :pipe)))
(is
(=
"This is not a pipe." (get-message :pipe "en-GB, fr-FR;q=0.9")))
(is (= "это не труба." (get-message :pipe "de-DE" "i18n" "ru")))
(is (= "froboz" (get-message :froboz)))))
(testing "Final fall through if no suitable language found"
(binding [*config* (assoc *config* :default-language "de-DE")]
;; there is no 'de-DE' language resource in the resources,
;; and that's exactly why we've chosen it for this test.
(is (= "pipe" (get-message :pipe)))))
(testing "Deprecated variables still work"
(binding [*config* nil
*default-language* "en-GB"]
(is (= "This is not a pipe." (get-message :pipe)))
(is
(= "Ceci n'est pas une pipe."
(get-message :pipe "en-GB;q=0.9, fr-FR"))))
(binding [*config* nil
*default-language* "ru"]
(is (= "это не труба." (get-message :pipe))))))
"Ceci n'est pas une pipe." (get-message :pipe "en-GB;q=0.9, fr-FR")))
(is (= "это не труба." (get-message :pipe "de-DE" "i18n" "ru"))))))