po_to_json-2.0.0/0000755000004100000410000000000014544003576013722 5ustar www-datawww-datapo_to_json-2.0.0/lib/0000755000004100000410000000000014544003576014470 5ustar www-datawww-datapo_to_json-2.0.0/lib/po_to_json.rb0000644000004100000410000001465514544003576017201 0ustar www-datawww-data# # Copyright (c) 2012-2015 Dropmysite.com # Copyright (c) 2015 Webhippie # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # gem "json", version: ">= 1.6.0" require "json" class PoToJson autoload :Version, File.expand_path("po_to_json/version", __dir__) attr_accessor :files, :glue, :options def initialize(files, glue = "|") @files = files @glue = glue end def generate_for_jed(language, overwrite = {}) @options = parse_options(overwrite.merge(language: language)) @parsed ||= inject_meta(parse_document) generated = build_json_for(build_jed_for(@parsed)) [ @options[:variable_locale_scope] ? "var" : "", "#{@options[:variable]} = #{@options[:variable]} || {};", "#{@options[:variable]}['#{@options[:language]}'] = #{generated};" ].join(" ") end def generate_for_json(language, overwrite = {}) @options = parse_options(overwrite.merge(language: language)) @parsed ||= inject_meta(parse_document) generated = build_json_for(build_json_for(@parsed)) raise "Not implemented yet, current value is #{generated}!" end def parse_document reset_buffer reset_result File.foreach(files) do |line| matches_values_for(line.chomp) end flush_buffer parse_header values end def flush_buffer return unless buffer[:msgid] build_trans assign_trans reset_buffer end def parse_header return if reject_header values[""][0].split("\\n").each do |line| next if line.empty? build_header_for(line) end values[""] = headers end def reject_header if values[""].nil? || values[""][0].nil? values[""] = {} true else false end end protected def trans @trans ||= [] end def errors @errors ||= [] end def values @values ||= {} end def buffer @buffer ||= {} end def headers @headers ||= {} end def lastkey @lastkey ||= "" end def reset_result @values = {} @errors = [] end def reset_buffer @buffer = {} @trans = [] @lastkey = "" end def detect_ctxt msgctxt = buffer[:msgctxt] msgid = buffer[:msgid] if msgctxt && !msgctxt.empty? [msgctxt, glue, msgid].join("") else msgid end end def detect_plural plural = buffer[:msgid_plural] plural if plural && !plural.empty? end def build_trans buffer.each do |key, string| trans[$1.to_i] = string if key.to_s =~ /^msgstr_(\d+)/ end # trans.unshift(detect_plural) if detect_plural end def assign_trans values[detect_ctxt] = trans unless trans.empty? end def push_buffer(value, key = nil) value = $1 if value =~ /^"(.*)"/ value.gsub!(/\\"/, "\"") if key.nil? buffer[lastkey] = [ buffer[lastkey], value ].join("") else buffer[key] = value @lastkey = key end end def parse_options(options) defaults = { pretty: false, domain: "app", variable: "locales", variable_locale_scope: true } defaults.merge(options) end def inject_meta(hash) hash[""]["lang"] ||= options[:language] hash[""]["domain"] ||= options[:domain] hash[""]["plural_forms"] ||= hash[""]["Plural-Forms"] hash end def build_header_for(line) if line =~ /(.*?):(.*)/ key = $1 value = $2 if headers.key? key errors.push "Duplicate header: #{line}" elsif key =~ /#-#-#-#-#/ errors.push "Marked header: #{line}" else headers[key] = value.strip end else errors.push "Malformed header: #{line}" end end def build_json_for(hash) if options[:pretty] JSON.pretty_generate(hash) else JSON.generate(hash) end end def build_jed_for(hash) { domain: options[:domain], locale_data: { options[:domain] => hash } } end def matches_values_for(line) return if generic_rejects? line return if generic_detects? line return if iterate_detects_for(line) errors.push "Strange line #{line}" end def iterate_detects_for(line) specific_detects.each do |detect| match = line.match(detect[:regex]) if match if detect[:index] push_buffer(match[detect[:index]], detect[:key].call(match)) else push_buffer(line) end return true end end false end def generic_rejects?(line) if line.match(/^$/) || line.match(/^(#[^~]|\#$)/) flush_buffer && true else false end end def generic_detects?(line) match = line.match(/^(?:#~ )?msgctxt\s+(.*)/) if match push_buffer( match[1], :msgctxt ) return true end false end def specific_detects [{ regex: /^(?:#~ )?msgctxt\s+(.*)/, index: 1, key: proc { :msgctxt } }, { regex: /^(?:#~ )?msgid\s+(.*)/, index: 1, key: proc { :msgid } }, { regex: /^(?:#~ )?msgid_plural\s+(.*)/, index: 1, key: proc { :msgid_plural } }, { regex: /^(?:#~ )?msgstr\s+(.*)/, index: 1, key: proc { :msgstr_0 } }, { regex: /^(?:#~ )?msgstr\[0\]\s+(.*)/, index: 1, key: proc { :msgstr_0 } }, { regex: /^(?:#~ )?msgstr\[(\d+)\]\s+(.*)/, index: 2, key: proc { |m| "msgstr_#{m[1]}".to_sym } }, { regex: /^(?:#~ )?"/, index: nil }] end end po_to_json-2.0.0/lib/po_to_json/0000755000004100000410000000000014544003576016641 5ustar www-datawww-datapo_to_json-2.0.0/lib/po_to_json/version.rb0000644000004100000410000000255714544003576020664 0ustar www-datawww-data# # Copyright (c) 2012-2015 Dropmysite.com # Copyright (c) 2015 Webhippie # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # class PoToJson class Version MAJOR = 2 MINOR = 0 PATCH = 0 PRE = nil class << self def to_s [MAJOR, MINOR, PATCH, PRE].compact.join(".") end end end end po_to_json-2.0.0/LICENSE0000644000004100000410000000221714544003576014731 0ustar www-datawww-dataThe MIT License (MIT) Copyright (c) 2012-2015 Dropmysite.com Copyright (c) 2015 Webhippie Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. po_to_json-2.0.0/README.md0000644000004100000410000000635114544003576015206 0ustar www-datawww-data# po_to_json [![Test Status](https://github.com/webhippie/po_to_json/actions/workflows/testing.yml/badge.svg)](https://github.com/webhippie/po_to_json/actions/workflows/testing.yaml) [![Join the Matrix chat at https://matrix.to/#/#webhippie:matrix.org](https://img.shields.io/badge/matrix-%23webhippie%3Amatrix.org-7bc9a4.svg)](https://matrix.to/#/#webhippie:matrix.org) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/6e015952f83d42d4bfc7e335d856554a)](https://app.codacy.com/gh/webhippie/po_to_json/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) [![Gem Version](https://badge.fury.io/rb/po_to_json.svg)](https://badge.fury.io/rb/po_to_json) Convert gettext PO files to JSON to use in your javascript app, based on po2json.pl by [DuckDuckGo, Inc.](http://duckduckgo.com/). Ideally you'll use this on a Rake task that creates JSON versions of your PO files, which can later be used from javascript with [Jed](http://slexaxton.github.io/Jed/) ## Versions For a list of the tested and supported Ruby and JSON versions please take a look at the [wokflow][workflow]. ## Installation ```ruby gem "po_to_json", "~> 2.0" ``` ## Versioning This library aims to adhere to [Semantic Versioning 2.0.0][semver]. Violations of this scheme should be reported as bugs. Specifically, if a minor or patch version is released that breaks backward compatibility, a new version should be immediately released that restores compatibility. Breaking changes to the public API will only be introduced with new major versions. As a result of this policy, you can (and should) specify a dependency on this gem using the [Pessimistic Version Constraint][pvc] with two digits of precision. For example: ```ruby spec.add_dependency "po_to_json", "~> 2.0" ``` ## Usage Most common use would be to generate a Jed ready javascript file. For example, in a Rails project: ```ruby require "po_to_json" json = PoToJson.new( Rails.root.join("locale", "de", "app.po") ).generate_for_jed("de") Rails.root.join( "app", "assets", "javascripts", "locale", "de", "app.js" ).write(json) ``` If you need a pretty json, add `pretty: true` to `generate_for_jed`, like the following example: ```ruby require "po_to_json" json = PoToJson.new( Rails.root.join("locale", "de", "app.po") ).generate_for_jed("de", pretty: true) Rails.root.join( "app", "assets", "javascripts", "locale", "de", "app.js" ).write(json) ``` The javascript file generated has a global "locales" object with an attribute corresponding to the generated language: ```javascript i18n = new Jed(locales["de"]) i18n.gettext("Hello World") // Should evaluate to "Hallo Welt" ``` ## Contributing Fork -> Patch -> Spec -> Push -> Pull Request ## Authors * [Thomas Boerger](https://github.com/tboerger) * [Nubis](https://github.com/nubis) * [Other contributors](https://github.com/webhippie/po_to_json/graphs/contributors) ## License MIT ## Copyright ``` Copyright (c) 2012-2015 Dropmysite.com Copyright (c) 2015 Webhippie ``` [workflow]: https://github.com/webhippie/po_to_json/blob/master/.github/workflows/testing.yml [semver]: http://semver.org [pvc]: http://guides.rubygems.org/patterns/#pessimistic-version-constraint po_to_json-2.0.0/CHANGELOG.md0000644000004100000410000000150414544003576015533 0ustar www-datawww-data# Changelog ## [2.0.0](https://github.com/webhippie/po_to_json/releases/tag/v2.0.0) - 2023-07-18 * Fix escape double quote in msgid (@chaomao) ## [1.1.0](https://github.com/webhippie/po_to_json/releases/tag/v1.0.1) - 2023-04-28 * Optionally remove var keyword to use a global (@illiatdesdindes) ## [1.0.1](https://github.com/webhippie/po_to_json/releases/tag/v1.0.1) - 2015-11-03 * Stop using bundler within the core lib (@tboerger) ## [1.0.0](https://github.com/webhippie/po_to_json/releases/tag/v1.0.0) - 2015-03-19 * BREAKING: Made result compatible to current Jed (#4) ## [0.1.0](https://github.com/webhippie/po_to_json/releases/tag/v0.1.0) - 2015-02-19 * Transfer from github.com/nubis/po_to_json (@tboerger) * Added TravisCI, Rubocop and Coveralls (@tboerger) * Updated structure to my opinionated gem style (@tboerger) po_to_json-2.0.0/po_to_json.gemspec0000644000004100000410000000346214544003576017445 0ustar www-datawww-data######################################################### # This file has been automatically generated by gem2tgz # ######################################################### # -*- encoding: utf-8 -*- # stub: po_to_json 2.0.0 ruby lib Gem::Specification.new do |s| s.name = "po_to_json".freeze s.version = "2.0.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Thomas Boerger".freeze, "Nubis".freeze] s.date = "2023-07-18" s.description = " Convert gettext PO files to JSON objects so that you can use it in your\n application.\n".freeze s.email = ["thomas@webhippie.de".freeze, "nubis@woobiz.com.ar".freeze] s.files = ["CHANGELOG.md".freeze, "LICENSE".freeze, "README.md".freeze, "lib/po_to_json.rb".freeze, "lib/po_to_json/version.rb".freeze] s.homepage = "https://github.com/webhippie/po_to_json".freeze s.licenses = ["MIT".freeze] s.required_ruby_version = Gem::Requirement.new(">= 1.9.3".freeze) s.rubygems_version = "3.3.15".freeze s.summary = "Convert gettext PO files to JSON".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_runtime_dependency(%q.freeze, [">= 1.6.0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 1.6.0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end