解决Jekyll不支持中文名和路径

3.4k 词

解决Jekyll不支持中文名和路径

Jekyll如果在Mac系统中,目录有中文字,生成新文件的时候会报错,主要原因是因为Ruby做字符串连接的时候,不支持中文,这样需要把一些字符,通过.force_encoding(“UTF-8”)转换成中文这样就不出错。 在部署的时候, 不是直接用GitPages的Jekyll服务,而且生成HTML静态文件,所以Github上 Jekyll支持不支持中文字符没关系, 本地Jekyll生成文件的时候不出错就达到目的了。

因为用的是rbenv虚拟的ruby运行环境,有多个ruby运行环境,代码改动的位置,在对应的Ruby版本目录下进行修改。

/Users/username/.rbenv/versions/2.7.2/lib/ruby/2.7.0/webrick/httpservlet/filehandler.rb

在这个文件中有一个,set_filename方法,把base这个变量强制改成base.force_encoding(“UTF-8”)))
Jekyll项目所在的系统路径中出现中文,


def set_filename(req, res)
       res.filename = @root.dup
       path_info = req.path_info.scan(%r|/[^/]*|)

       path_info.unshift("")  # dummy for checking @root dir
       while base = path_info.first
         break if base == "/"
         break unless File.directory?(File.expand_path(res.filename + base.force_encoding("UTF-8")))
         shift_path_info(req, res, path_info)
         call_callback(:DirectoryCallback, req, res)
       end

不支持中文的问题, 不限于只有本地路径有中文,还有其他与中文字符连接的时候都有这个问题。比如,文件名, title名,各种属性的设置都有可能不支持中文,基本的解决方法原则,就转成UTF-8字符再进行字符连接。
Jekyll在读取中文目录的时间报错,不能实时的监控文件变化,一遇到变更中文文件名的markdown文件就出错。
根本原因, 在原有英文代码里,没有考虑bit asc与UTF-8数据join连接造成的出错。

出现问题呢的文件是:

/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/pathname.rb

解决的方法是直接修改源码:

原始代码:

def children(with_directory=true)
    with_directory = false if @path == '.'
    result = []
    Dir.foreach(@path) {|e|
      next if e == '.' || e == '..'
      if with_directory
        result << self.class.new(File.join(@path, e))
      else
        result << self.class.new(e)
      end
    }
    result
  end

修改代码,如下:

def children(with_directory=true)
    with_directory = false if @path == '.'
    result = []
    Dir.foreach(@path) {|e|
      next if e == '.' || e == '..'
      if with_directory
        #print e, "\n"
        #print @path, "\n"
        result << self.class.new(File.join(@path.force_encoding("UTF-8"), e))
      else
        result << self.class.new(e)
      end
    }
    result
  end

关键的地方是,是将@path变成 @path.force_encoding(“UTF-8”) , 这样就可以和后面的“e"的UTF-8的内容进行join字符串连接了。

这样修改问题就解决了。

要是出现了“Encoding::CompatibilityError: incompatible character encodings: UTF-8 and GBK”

有可能是之前设置成了:

chcp 850

改回

chcp 936

这个改环境,而不是文件的编码格式,如果不想改文件的编码格式就,可以直接把UTF-8改成GBK,这个问题也解决了。

result << self.class.new(File.join(@path.force_encoding("GBK"), e))

后来又出问题了,在Windows10上用choco装的Jekyll是3.x,用的Ruby也是是3.x但是, Bunlde是 2.2, Bundle install 出来的Jekyll是 4.x,最后运行不起来有,少了webrick,gem install 装了也装不到4.x中,Bundle Update也没用,就把Ruby降级到了2.7好用了,但是,又不支持中文名了。

C:/tools/Ruby27-x64/lib/ruby/gems/2.7.0/gems/liquid-4.0.3/lib/liquid/block_body.rb

直接改了, 和上面的思路一样,强转。

def render(context)
  output = []
  context.resource_limits.render_score += @nodelist.length

  idx = 0
  while node = @nodelist[idx]
    case node
    when String
      check_resources(context, node)
      output << node
    when Variable
      render_node_to_output(node, output, context)
    when Block
      render_node_to_output(node, output, context, node.blank?)
      break if context.interrupt? # might have happened in a for-block
    when Continue, Break
      # If we get an Interrupt that means the block must stop processing. An
      # Interrupt is any command that stops block execution such as {% break %}
      # or {% continue %}
      context.push_interrupt(node.interrupt)
      break
    else # Other non-Block tags
      render_node_to_output(node, output, context)
      break if context.interrupt? # might have happened through an include
    end
    idx += 1
  end
  output = output.map{ |i| i.dup.force_encoding("UTF-8") }
  output.join
end

private

就在

output.join

的前面硬加一句

output = output.map{ |i| i.dup.force_encoding("UTF-8") }

然后就好用了。

在Windows平台上还有一个问题,在WSL1升级成WSL2之后, Jekyll的自动生成功能不好用了,VSC的Jekyll Run插件也不好用,这时候需要加一句。

--force-polling

加全了就是

--watch --trace --incremental  --force-polling

这样Jekyll在WSL、PowerShell中,就又可以自动根据文件变更,重新将Markdown自动生成新的HTML文件里。一个是解决是文件名不支持中文,一个是路径不支持中文,以上的修改都是解决这些问题的。后期为了生产速度和便利性,用Node JS的Hexo做博客系统更方便一些。