class YARD::I18n::PotGenerator
The PotGenerator
generates POT format string from {CodeObjects::Base} and {CodeObjects::ExtraFileObject}.
POT and PO¶ ↑
POT is an acronym for “Portable Object
Template”. POT is a template file to create PO file. The extension for POT is “.pot”. PO file is an acronym for “Portable Object”. PO file has many parts of message ID (msgid) that is translation target message and message string (msgstr) that is translated message of message ID. If you want to translate “Hello” in English into “Bonjour” in French, “Hello” is the msgid ID and “Bonjour” is msgstr. The extension for PO is “.po”.
How to extract msgids¶ ↑
The PotGenerator
has two parse methods:
-
{#parse_objects} for {CodeObjects::Base}
-
{#parse_files} for {CodeObjects::ExtraFileObject}
{#parse_objects} extracts msgids from docstring and tags of {CodeObjects::Base} objects. The docstring of {CodeObjects::Base} object is parsed and a paragraph is extracted as a msgid. Tag name and tag text are extracted as msgids from a tag.
{#parse_files} extracts msgids from {CodeObjects::ExtraFileObject} objects. The file content of {CodeObjects::ExtraFileObject} object is parsed and a paragraph is extracted as a msgid.
Usage¶ ↑
To create a .pot file by PotGenerator
, instantiate a PotGenerator
with a relative working directory path from a directory path that has created .pot file, parse {CodeObjects::Base} objects and {CodeObjects::ExtraFileObject} objects, generate a POT and write the generated POT to a .pot file. The relative working directory path is “..” when the working directory path is “.” and the POT is wrote into “po/yard.pot”.
@example Generate a .pot file
po_file_path = "po/yard.pot" po_file_directory_pathname = Pathname.new(po_file_path).directory) working_directory_pathname = Pathname.new(".") relative_base_path = working_directory_pathname.relative_path_from(po_file_directory_pathname).to_s # relative_base_path -> ".." generator = YARD::I18n::PotGenerator.new(relative_base_path) generator.parse_objects(objects) generator.parse_files(files) pot = generator.generate po_file_directory_pathname.mkpath File.open(po_file_path, "w") do |pot_file| pot_file.print(pot) end
@see www.gnu.org/software/gettext/manual/html_node/PO-Files.html
GNU gettext manual about details of PO file
Attributes
Extracted messages.
@return [Messages] @since 0.8.1
Public Class Methods
Creates a POT generator that uses relative_base_path
to generate locations for a msgid. relative_base_path
is prepended to all locations.
@param [String] relative_base_path a relative working
directory path from a directory path that has created .pot file.
# File lib/yard/i18n/pot_generator.rb, line 79 def initialize(relative_base_path) @relative_base_path = relative_base_path @extracted_objects = {} @messages = Messages.new end
Public Instance Methods
Generates POT from +@messages+.
One PO file entry is generated from a Message
in +@messages+.
Locations of the Message
are used to generate the reference line that is started with “#: ”. relative_base_path
passed when the generater is created is prepended to each path in location.
Comments of the Message
are used to generate the translator-comment line that is started with “# ”.
@return [String] POT format string
# File lib/yard/i18n/pot_generator.rb, line 122 def generate pot = String.new(header) sorted_messages = @messages.sort_by do |message| sorted_locations = message.locations.sort sorted_locations.first || [] end sorted_messages.each do |message| generate_message(pot, message) end pot end
Parses {CodeObjects::ExtraFileObject} objects and stores extracted msgids into {#messages}.
@param [Array<CodeObjects::ExtraFileObject>] files a list
of {CodeObjects::ExtraFileObject} objects to be parsed.
@return [void]
# File lib/yard/i18n/pot_generator.rb, line 103 def parse_files(files) files.each do |file| extract_paragraphs(file) end end
Parses {CodeObjects::Base} objects and stores extracted msgids into {#messages}
@param [Array<CodeObjects::Base>] objects a list of
{CodeObjects::Base} to be parsed.
@return [void]
# File lib/yard/i18n/pot_generator.rb, line 91 def parse_objects(objects) objects.each do |object| extract_documents(object) end end
Private Instance Methods
# File lib/yard/i18n/pot_generator.rb, line 160 def current_time @current_time ||= Time.now end
# File lib/yard/i18n/pot_generator.rb, line 183 def escape_message_id(message_id) message_id.gsub(/(\\|")/) do special_character = $1 "\\#{special_character}" end end
# File lib/yard/i18n/pot_generator.rb, line 194 def extract_documents(object) return if @extracted_objects.key?(object) @extracted_objects[object] = true case object when CodeObjects::NamespaceObject object.children.each do |child| extract_documents(child) end end if object.group message = register_message(object.group) object.files.each do |path, line| message.add_location(path, line) end message.add_comment(object.path) unless object.path.empty? end docstring = object.docstring unless docstring.empty? text = Text.new(StringIO.new(docstring)) text.extract_messages do |type, *args| case type when :paragraph paragraph, line_no = *args message = register_message(paragraph.rstrip) object.files.each do |path, line| message.add_location(path, (docstring.line || line) + line_no) end message.add_comment(object.path) unless object.path.empty? else raise "should not reach here: unexpected type: #{type}" end end end docstring.tags.each do |tag| extract_tag_documents(tag) end end
# File lib/yard/i18n/pot_generator.rb, line 268 def extract_paragraphs(file) File.open(file.filename) do |input| text = Text.new(input, :have_header => true) text.extract_messages do |type, *args| case type when :attribute name, value, line_no = *args message = register_message(value) message.add_location(file.filename, line_no) message.add_comment(name) when :paragraph paragraph, line_no = *args message = register_message(paragraph.rstrip) message.add_location(file.filename, line_no) else raise "should not reach here: unexpected type: #{type}" end end end end
# File lib/yard/i18n/pot_generator.rb, line 235 def extract_tag_documents(tag) extract_tag_name(tag) extract_tag_text(tag) extract_documents(tag) if Tags::OverloadTag === tag end
# File lib/yard/i18n/pot_generator.rb, line 242 def extract_tag_name(tag) return if tag.name.nil? return if tag.name.is_a?(String) && tag.name.empty? key = "tag|#{tag.tag_name}|#{tag.name}" message = register_message(key) tag.object.files.each do |path, line| message.add_location(path, line) end tag_label = String.new("@#{tag.tag_name}") tag_label << " [#{tag.types.join(', ')}]" if tag.types message.add_comment(tag_label) end
# File lib/yard/i18n/pot_generator.rb, line 255 def extract_tag_text(tag) return if tag.text.nil? return if tag.text.empty? message = register_message(tag.text) tag.object.files.each do |path, line| message.add_location(path, line) end tag_label = String.new("@#{tag.tag_name}") tag_label << " [#{tag.types.join(', ')}]" if tag.types tag_label << " #{tag.name}" if tag.name message.add_comment(tag_label) end
# File lib/yard/i18n/pot_generator.rb, line 168 def generate_message(pot, message) message.comments.sort.each do |comment| pot << "# #{comment}\n" unless comment.empty? end message.locations.sort.each do |path, line| pot << "#: #{@relative_base_path}/#{path}:#{line}\n" end escaped_message_id = escape_message_id(message.id) escaped_message_id = escaped_message_id.gsub(/\n/, "\\\\n\"\n\"") pot << "msgid \"#{escaped_message_id}\"\n" pot << "msgstr \"\"\n" pot << "\n" pot end
# File lib/yard/i18n/pot_generator.rb, line 164 def generate_pot_creation_date_value current_time.strftime("%Y-%m-%d %H:%M%z") end
# File lib/yard/i18n/pot_generator.rb, line 136 def header <<-EOH # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\\n" "Report-Msgid-Bugs-To: \\n" "POT-Creation-Date: #{generate_pot_creation_date_value}\\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n" "Language-Team: LANGUAGE <LL@li.org>\\n" "Language: \\n" "MIME-Version: 1.0\\n" "Content-Type: text/plain; charset=UTF-8\\n" "Content-Transfer-Encoding: 8bit\\n" EOH end
# File lib/yard/i18n/pot_generator.rb, line 190 def register_message(id) @messages.register(id) end