Repository: tlienart/Franklin.jl
Pull request #433 (2020-03-28 04:50:57)

Add language customization to dates
This is a workaround I made for my site so I can define custom names for the months of the year and days of the week, and their abbreviations. As I am using the `locale` functionality of `Dates`, I'll be calling it "locale" customization.

The usage is simple, and like `date_format`, the user can set some local/global variables:
 - `date_days` : list with the names for days of the week
 - `date_shortdays` : list with the abbreviated names for the days of the week
 - `date_months` : list with the names of months
 - `date_shortmonths` : list with the abbreviated names of months

If any of the `short` variations are not set, the `fd_date` function tries to automatically create those by using the first three characters of the names of months or days of week.

Maybe this is not the right way to implement it, but as I have done it anyway, I present this as my first contribution :upside_down_face: I also don't know the proper way to add tests to this, should it be like the `cond-insert` tests?

tlienart: Oh great, thanks a lot! I’ll review this later today.

Re tests: generally I think regression tests would be good I.e: just write a test showing what your code is supposed to do. 

The place doesn’t matter so much, but maybe `tests/utils`

Thanks again!
tlienart: Your PR actually makes me realize there are a few shortcomings in Franklin in terms of how dates are processed and actually there were thoughts on this in #14 in particular, at the moment if someone does `@def date = ...` and then `{{fill date}}` it actually doesn't use the formatting. Some thoughts should go into this.

Anyway your PR is fine and it will apply to `fd_ctime` and `fd_mtime` which can be used in footer etc, that's already very useful. 

Here's a way to test your PR, kindly extend it to tests the other lists, possibly use other languages too :) 

```
s = raw"""
   @def date_format = "e, d u Y"
   @def date_months = ["janvier", "février", "mars", "avril", "mai", "juin",
                       "juillet", "août", "septembre", "octobre", "novembre", 
                       "décembre"];
   @def date_shortmonths = ["janv","févr","mars","avril","mai","juin",
                            "juil","août","sept","oct","nov","déc"];
   @def date_days = ["lundi","mardi","mercredi","jeudi",
                     "vendredi","samedi","dimanche"];
   @def reeval = true
   ```julia:ex
   #hideall
   using Franklin, Dates
   println(Franklin.fd_date(DateTime("1996-01-01T12:30:00")))
   ```
   \textoutput{ex}
   """ |> fd2html_td
@test isapproxstr(s, "lun, 1 jan 1996")
```
tlienart: Sorry for the comments, I tested your branch locally and a few more things occurred to me along the way.

Thanks a lot for your contribution!
lucasvreis: Where should I put the tests inside `tests/utils`, in a new file or existing one? And thank you for your comments, I'm still leaning Julia.
codecov[bot]: # [Codecov](https://codecov.io/gh/tlienart/Franklin.jl/pull/433?src=pr&el=h1) Report
> Merging [#433](https://codecov.io/gh/tlienart/Franklin.jl/pull/433?src=pr&el=desc) into [master](https://codecov.io/gh/tlienart/Franklin.jl/commit/fc6f4abf0b7f7ad955ddb31a5fcf0898e2083e93?src=pr&el=desc) will **decrease** coverage by `0.22%`.
> The diff coverage is `53.84%`.

[![Impacted file tree graph](https://codecov.io/gh/tlienart/Franklin.jl/pull/433/graphs/tree.svg?width=650&token=6aP21CmJcY&height=150&src=pr)](https://codecov.io/gh/tlienart/Franklin.jl/pull/433?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #433      +/-   ##
==========================================
- Coverage    89.4%   89.17%   -0.23%     
==========================================
  Files          40       40              
  Lines        2095     2107      +12     
==========================================
+ Hits         1873     1879       +6     
- Misses        222      228       +6
```


| [Impacted Files](https://codecov.io/gh/tlienart/Franklin.jl/pull/433?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [src/utils/vars.jl](https://codecov.io/gh/tlienart/Franklin.jl/pull/433/diff?src=pr&el=tree#diff-c3JjL3V0aWxzL3ZhcnMuamw=) | `89.83% <53.84%> (-10.17%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/tlienart/Franklin.jl/pull/433?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/tlienart/Franklin.jl/pull/433?src=pr&el=footer). Last update [fc6f4ab...76d345d](https://codecov.io/gh/tlienart/Franklin.jl/pull/433?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

lucasvreis: Soo, I added some tests and also tested it in my blog. I am able to set a language in the `config.md` file and then overwrite it with local variables in the page. But for some weird reason the japanese language test fails if I don't set a date different from the previous test, else it just reuses the output from the last test. You can see the other japanese test where I change the date runs properly. Very strange.
tlienart: > Where should I put the tests inside `tests/utils`, in a new file or existing one? And thank you for your comments, I'm still learning Julia.

Please put them in `tests/utils/paths_vars.jl` at the end :) 
tlienart: Ok this is great, thanks a lot! Ignore my last comment, I'll do it, thanks again 😄 

Patch:
diff --git a/src/utils/vars.jl b/src/utils/vars.jl
index bbb8d85f..d452b230 100644
--- a/src/utils/vars.jl
+++ b/src/utils/vars.jl
@@ -14,6 +14,10 @@ const GLOBAL_VARS_DEFAULT = [
     # General
     "author"           => Pair("THE AUTHOR",   (String, Nothing)),
     "date_format"      => Pair("U dd, yyyy",   (String,)),
+    "date_months"      => Pair(String[],       (Vector{String},)),
+    "date_shortmonths" => Pair(String[],       (Vector{String},)),
+    "date_days"        => Pair(String[],       (Vector{String},)),
+    "date_shortdays"   => Pair(String[],       (Vector{String},)),
     "prepath"          => Pair("",             (String,)),
     # will be added to IGNORE_FILES
     "ignore"           => Pair(String[],       (Vector{String},)),
@@ -180,10 +184,40 @@ Convenience functions related to the page vars
 ============================================= =#
 
 """
+$(SIGNATURES)
+
 Convenience function taking a `DateTime` object and returning the corresponding
-formatted string with the format contained in `LOCAL_VARS["date_format"]`.
-"""
-fd_date(d::DateTime) = Dates.format(d, LOCAL_VARS["date_format"].first)
+formatted string with the format contained in `LOCAL_VARS["date_format"]` and 
+with the locale data provided in `date_months`, `date_shortmonths`, `date_days`, 
+and `date_shortdays` local variables. If `short` variations are not provided,
+automatically construct them using the first three letters of the names in
+`date_months` and `date_days`.
+"""
+function fd_date(d::DateTime)
+    # aliases for locale data and format from local variables
+    format      = locvar("date_format")
+    months      = locvar("date_months")
+    shortmonths = locvar("date_shortmonths")
+    days        = locvar("date_days")
+    shortdays   = locvar("date_shortdays")
+    # if vectors are empty, user has not defined custom locale,
+    # defaults to english
+    if all(isempty.((months, shortmonths, days, shortdays)))
+        return Dates.format(d, format, locale="english")
+    end
+    # if shortdays or shortmonths are undefined,
+    # automatically construct them from other lists
+    if !isempty(days) && isempty(shortdays)
+        shortdays = first.(days, 3)
+    end
+    if !isempty(months) && isempty(shortmonths)
+        shortmonths = first.(months, 3)
+    end
+    # set locale for this page
+    Dates.LOCALES["date_locale"] = Dates.DateLocale(months, shortmonths, 
+                                                    days, shortdays)
+    return Dates.format(d, format, locale="date_locale")
+end
 
 
 """


Test patch:
diff --git a/test/utils/misc.jl b/test/utils/misc.jl
index 9617b64a..2df789a1 100644
--- a/test/utils/misc.jl
+++ b/test/utils/misc.jl
@@ -125,3 +125,66 @@ end
     @test F.check_type(Vector{String},  (Vector{Any},))
     @test !F.check_type(Vector{String}, (Matrix{Any},))
 end
+
+@testset "Date locales" begin
+    s = raw"""
+    @def date_format = "e, d u Y"
+    @def date_months = ["janvier", "février", "mars", "avril", "mai", "juin",
+                        "juillet", "août", "septembre", "octobre", "novembre", 
+                        "décembre"];
+    @def date_shortmonths = ["janv","févr","mars","avril","mai","juin",
+                                "juil","août","sept","oct","nov","déc"];
+    @def date_days = ["lundi","mardi","mercredi","jeudi",
+                        "vendredi","samedi","dimanche"];
+    ```julia:ex1
+    #hideall
+    using Franklin, Dates
+    println(Franklin.fd_date(DateTime("1996-01-01T12:30:00")))
+    ```
+    \textoutput{ex1}
+    """ |> fd2html_td
+    @test isapproxstr(s, "lun, 1 janv 1996") # auto short names
+
+    s = raw"""
+    @def date_format = "d u Y"
+    @def date_months = ["janvier", "février", "mars", "avril", "mai", "juin",
+                        "juillet", "août", "septembre", "octobre", "novembre", 
+                        "décembre"];
+    ```julia:ex2
+    #hideall
+    using Franklin, Dates
+    println(Franklin.fd_date(DateTime("1996-12-01T12:30:00")))
+    ```
+    \textoutput{ex2}
+    """ |> fd2html_td
+    @test isapproxstr(s, "1 déc 1996") # accents in short names
+
+    s = raw"""
+    @def date_format = "d u Y"
+    @def date_shortmonths = ["janv","févr","mars","avril","mai","juin",
+                                "juil","août","sept","oct","nov","déc"];
+    ```julia:ex3
+    #hideall
+    using Franklin, Dates
+    println(Franklin.fd_date(DateTime("1996-01-01T12:30:00")))
+    ```
+    \textoutput{ex3}
+    """ |> fd2html_td
+    @test isapproxstr(s, "1 janv 1996") # only short names defined
+
+    s = raw"""
+    @def date_format = "Y年ud日　E"
+    @def date_months = ["1月", "2月", "3月", "4月", "5月", "6月",
+                        "7月", "8月", "9月", "10月", "11月", "12月"];
+
+    @def date_days = ["月曜日","火曜日","水曜日","木曜日",
+                        "金曜日","土曜日","日曜日"];
+    ```julia:ex4
+    #hideall
+    using Franklin, Dates
+    println(Franklin.fd_date(DateTime("1996-01-01T12:30:00")))
+    ```
+    \textoutput{ex4}
+    """ |> fd2html_td
+    @test isapproxstr(s, "1996年1月1日　月曜日") # japanese and unicode
+end