JuliaCN/julia_zh_cn

文档翻译方案

Closed this issue · 7 comments

目前Julia的源码采用Documenter.jl收集文档. 这个issue用来讨论怎么将中文文档加入到原生的代码里.

方案1请参看 JuliaCN/juliacn 这个repo

缺点是这个方案对REPL会build出一个新的binary.

方案2 修改Docs这个module, 让Multi Docs能筛选语言标签(或者另外开发一个package用来支持i18n的语言标签筛选) 这个工程量可能比方案1大

EDIT:

In fact, @doc is enough, it's simply: eval(Base.Math, quote @doc "aaaaa" sin(x) end). 😅

tl;dr

Documenter REPL Juno Documentation
@doc(submodule)
DocStr(submodule)
@doc(main)
DocStr(main)

今晚试了一下,只用当前Docs的API也可以覆盖原文档。

@doc覆盖

using Documenter
@doc "aaa" Base.Iterators.product
makedocs(format = :html, sitename = "test", pages = Any["Index" => "index.md"])

Documenter只生成aaa,可以正确覆盖原文档,但REPL里只能增量添加,没有覆盖:

help?> Iterators.product
  product(iters...)

  Returns an iterator over the product of several iterators. Each generated element is a tuple
  whose ith element comes from the ith argument iterator. The first iterator changes the fastest.
  Example:

     Example
    ≡≡≡≡≡≡≡≡≡

  julia> collect(Iterators.product(1:2,3:5))
  2×3 Array{Tuple{Int64,Int64},2}:
   (1, 3)  (1, 4)  (1, 5)
   (2, 3)  (2, 4)  (2, 5)

  aaa

并且在Juno的Documentation里搜索product也会出来两个结果。

直接改DocStr

using Base.Docs: Binding, meta, MultiDoc

md = get!(meta(Base.Iterators), Binding(Base.Iterators, :product), MultiDoc())

md.docs[md.order[]].text = Core.svec("bbbbbb")

help?> Iterators.product
  bbbbbb

在Documenter,REPL以及Juno的Documentation里均可以正确覆盖,但只适用于submodule中的函数,对于sin函数无效:

using Base.Docs: Binding, meta, MultiDoc

md = get!(meta(Base.Math), Binding(Base.Math, :sin), MultiDoc())

md.docs[md.order[]].text = Core.svec("ssssssss")

help?> sin
search: sin sinh sind sinc sinpi asin using isinf asinh asind isinteger isinteractive sign signif

  sin(x)

  Compute sine of x, where x is in radians.

help?> Base.Math.sin
  sin(x)

  Compute sine of x, where x is in radians.

Documenter生成的和REPL显示的还是原来的文档,只有在Juno的Documentation里搜索的结果是覆盖的。最终的结果应该跟文档显示的实现方式有关,所以文档的html发布和REPL显示这两个功能还是分开考虑比较好?

我试验了一下, 大致理解了Docs是怎么存的了.

首先是meta这个函数, 用来获取某个module下的Binding => MultiDoc 的一个Dict.

using Base.Docs: Binding, meta
doclist = meta(Base.Math) # 这里获得了Base.Math这个module下面所有的文档

接下来去这个Dict里找sin函数对应的MultiDoc然后修改它.

sindoc = doclist[Binding(Base, :sin)]

然后我们看一下sindoc的成员, 有两个

sindoc.docs
sindoc.order
  • docs 里面是一个ObjectIdDict对象, 里面存储的是一个sig (sig作为函数前面一般就是说一个用Tuple{A, B, ...}这样存下来的函数变量的类型的Tuple类型)
  • order 里面是函数的(被标记了文档的, 比如sin被标记的那个是Any类型的输入) 签名的显示顺序

我们要修改文档需要覆盖docs里的内容. 先取出其中一项(对sin来说只有一项), 键值为对应函数签名, 这里是Tuple{Any}

sindoc_content = sindoc.docs[Tuple{Any}]

这是一个DocStr对象, 这其中有三个成员: data, object, text

  • data: 存储一些meta信息, 和我们无关
  • object: 这里存储的应该是使用Markdown.parse渲染后的一个Nullable, 在外面套一个Nullable的用意应该是让这个内容变得不可修改(也就是immutable), 所以我们需要自己重新产生一个这样的Nullable
  • text: 这里是用Core.svec存储的原始字符串, 暂时不知道存储的用意, 但是也需要修改
sindoc_content.object = Nullable(Markdown.parse("这是一个正弦函数"))

实际上对于REPL来说修改了这里在help mode里搜索出的sin的文档就是中文的了.

@Roger-luo test是原始文档,object是parse之后的Markdown, 我之前只改了test,而没有删除旧的Markdown, 所以没有成功, 直接把object改成 nothing 就可以让它强制刷新:

julia> using Base.Docs: Binding, meta, MultiDoc

julia> md = get!(meta(Base.Math), Binding(Base.Math, :sin), MultiDoc())
Base.Docs.MultiDoc(Type[Tuple{Any}], ObjectIdDict(Pair{Any,Any}(Tuple{Any}, Base.Docs.DocStr(svec("    sin(x)\n\nCompute sine of `x`, where `x` is in radians.\n"), #NULL, Dict{Symbol,Any}(Pair{Symbol,Any}(:typesig, Tuple{Any}),Pair{Symbol,Any}(:module, Base.Math),Pair{Symbol,Any}(:linenumber, 303),Pair{Symbol,Any}(:binding, Base.sin),Pair{Symbol,Any}(:path, "math.jl"))))))

julia> md.docs[md.order[]].text = Core.svec("bbbbbb")
svec("bbbbbb")

julia> md.docs[md.order[]].object = nothing

help?> sin
search: sin sinh sind sinc sinpi asin using isinf asinh asind isinteger isinteractive sign signif signed Signed signbit

  bbbbbb

这样覆盖这个功能已经OK了,发布binary的方案1可以否了。

OK, 我明白了. 那我们就采用package吧. Package就用DocInject.jl这个repo可以么. 反正还没有添加内容. 那么现在大致思路就是用上面这个方法在DocInject这个包里提供一个替换文档的宏, 然后在另外一个package: JuliaCN.jl里提供中文文档, 并利用宏来注入中文. 大家还有啥意见没

不过我目前实现了一下这个宏, 很短, 其实

这个issue我就先关掉了,讨论到JuliaCN.jl下面继续吧

👌