Rails friendly id with non-Latin characters

只谈情不闲聊 提交于 2019-12-01 06:57:14

问题


I have a model which I use its friendly id as slug:

extend FriendlyId
friendly_id :slug_candidates, :use => :scoped, :scope => :account

def slug_candidates
  :title_and_sequence
end


def title_and_sequence
  slug = normalize_friendly_id(title)
      :
  # some login to add sequence in case of collision
      :
end

My problem is that when I use non-Latin chars (Arab, Hebrew,...) I get an empty slug. Is there any nice-and-easy solution?


UPDATE

Just to make my question clear, I would like to have the same behaviour as WordPress, which means:

+--------------------+----------------------------------------------------+
| Title              | url                                                |
+--------------------+----------------------------------------------------+
| Hello World!!      | /hello-world                                       |
+--------------------+----------------------------------------------------+
| Helló Világ        | /hello-vilag                                       |
+--------------------+----------------------------------------------------+
| שלום עולם          | /%D7%A9%D7%9C%D7%95%D7%9D-%D7%A2%D7%95%D7%9C%D7%9D |
+--------------------+----------------------------------------------------+
| مرحبا              | %D9%85%D8%B1%D8%AD%D8%A8%D8%A7                     |
+--------------------+----------------------------------------------------+

(both Arabic and Hebrew are translated in modern browsers to original and readable characters).


回答1:


There's a Rails API method for that transliterate

Example use:

transliterate('Ãrøskøbing')
# => "AEroskobing"

By default it only supports latin-based languages and Russian but you should be able to find rules for other alphabets as well (as explained in the linked doc)

EDIT
To achieve the same behaviour as wordpress you can simply use url encoding, as in example below

URI::encode('שלום') => "%D7%A9%D7%9C%D7%95%D7%9D"



回答2:


Thanks to @michalszyndel notes and ideas I managed to get the following solution, hope it will be helpful for more people.

First, how to make non-unicode chars in slug:

extend FriendlyId
friendly_id :slug_candidates, :use => :scoped, :scope => :account

def slug_candidates
  :title_and_sequence
end

def title_and_sequence
  # This line switch all special chars to its unicode
  title_unicode = heb_to_unicode(title)

  slug = normalize_friendly_id(title_unicode)
      :
  # some login to add sequence in case of collision
  # and whatever you need from your slug
      :
end

def heb_to_unicode(str)
  heb_chars = 'אבגדהוזחטיכךלמםנןסעפףצץקרשת'
  heb_map = {}
  heb_chars.split("").each {|c| heb_map.merge!({c => URI::encode(c)})}
  # This regex replace all Hebrew letters to their unicode representation
  heb_re = Regexp.new(heb_map.keys.map { |x| Regexp.escape(x) }.join('|'))

  return str.gsub(heb_re, heb_map)
end

I also needed to modify normalize_friendly_id in order to avoid it to get rid of the %.
I simply took the code of parameterize method and added % to the regex:

def normalize_friendly_id(string)
  # replace accented chars with their ascii equivalents
  parameterized_string = I18n.transliterate(string)

  sep = '-'

  # Turn unwanted chars into the separator
  # We permit % in order to allow unicode in slug
  parameterized_string.gsub!(/[^a-zA-Z0-9\-_\%]+/, sep)
  unless sep.nil? || sep.empty?
    re_sep = Regexp.escape(sep)
    # No more than one of the separator in a row.
    parameterized_string.gsub!(/#{re_sep}{2,}/, sep)
    # Remove leading/trailing separator.
    parameterized_string.gsub!(/^#{re_sep}|#{re_sep}$/, '')
  end
  parameterized_string.downcase
end

Now if I save a model with the title שלום its slug is saved as %D7%A9%D7%9C%D7%95%D7%9D.
In order to find the instance using the friendly method I need to do the following:

id = URI::encode(params[:id]).downcase
Page.friendly.find(id)


来源:https://stackoverflow.com/questions/33609872/rails-friendly-id-with-non-latin-characters

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!