# frozen_string_literal: truemoduleYARDmoduleI18n# Provides some convenient features for translating a text.classText# Creates a text object that has translation related features for# the input text.## @param [#each_line] input a text to be translated.# @option options [Boolean] :have_header (false) whether the# input text has header or not.definitialize(input,options={})@input=input@options=optionsend# Extracts translation target messages from +@input+.## @yield [:attribute, name, value, line_no] the block that# receives extracted an attribute in header. It may called many# times.# @yieldparam [String] name the name of extracted attribute.# @yieldparam [String] value the value of extracted attribute.# @yieldparam [Integer] line_no the defined line number of extracted# attribute.# @yield [:paragraph, text, start_line_no] the block that# receives extracted a paragraph in body. Paragraph is a text# block separated by one or more empty lines. Empty line is a# line that contains only zero or more whitespaces. It may# called many times.# @yieldparam [String] text the text of extracted paragraph.# @yieldparam [Integer] start_line_no the start line number of# extracted paragraph.# @return [void]defextract_messagesparsedo|part|casepart[:type]when:markup,:empty_line# ignorewhen:attributeyield(:attribute,part[:name],part[:value],part[:line_no])when:paragraphyield(:paragraph,part[:paragraph],part[:line_no])endendend# Translates into +locale+.## @param [Locale] locale the translation target locale.# @return [String] translated text.deftranslate(locale)translated_text=String.new("")parsedo|part|casepart[:type]when:markuptranslated_text<<part[:line]when:attributeprefix="#{part[:prefix]}#{part[:name]}#{part[:infix]}"value=locale.translate(part[:value])suffix=part[:suffix]translated_text<<"#{prefix}#{value}#{suffix}"when:paragraphtranslated_text<<locale.translate(part[:paragraph])when:empty_linetranslated_text<<part[:line]elseraise"should not reach here: unexpected type: #{type}"endendtranslated_textendprivatedefparse(&block)paragraph=String.new("")paragraph_start_line=0line_no=0in_header=@options[:have_header]@input.each_linedo|line|line_no+=1ifin_headercaselinewhen/^#!\S+\s*$/ifline_no==1emit_markup_event(line,line_no,&block)elsein_header=falseendwhen/^(\s*#\s*@)(\S+)(\s*)(.+?)(\s*)$/emit_attribute_event(Regexp.last_match,line_no,&block)elsein_header=falseifline.strip.empty?emit_empty_line_event(line,line_no,&block)nextendendnextifin_headerendcaselinewhen/^\s*$/ifparagraph.empty?emit_empty_line_event(line,line_no,&block)elseparagraph<<lineemit_paragraph_event(paragraph,paragraph_start_line,line_no,&block)paragraph=String.new("")endelseparagraph_start_line=line_noifparagraph.empty?paragraph<<lineendendunlessparagraph.empty?emit_paragraph_event(paragraph,paragraph_start_line,line_no,&block)endenddefemit_markup_event(line,line_no)part={:type=>:markup,:line=>line,:line_no=>line_no}yield(part)enddefemit_attribute_event(match_data,line_no)part={:type=>:attribute,:prefix=>match_data[1],:name=>match_data[2],:infix=>match_data[3],:value=>match_data[4],:suffix=>match_data[5],:line_no=>line_no}yield(part)enddefemit_empty_line_event(line,line_no)part={:type=>:empty_line,:line=>line,:line_no=>line_no}yield(part)enddefemit_paragraph_event(paragraph,paragraph_start_line,line_no,&block)paragraph_part={:type=>:paragraph,:line_no=>paragraph_start_line}match_data=/(\s*)\z/.match(paragraph)ifmatch_dataparagraph_part[:paragraph]=match_data.pre_matchyield(paragraph_part)emit_empty_line_event(match_data[1],line_no,&block)elseparagraph_part[:paragraph]=paragraphyield(paragraph_part)endendendendend