-
Notifications
You must be signed in to change notification settings - Fork 264
Custom CSV import and export tasks
lorint edited this page Jan 10, 2020
·
10 revisions
These custom tasks for CSV import and export were originally posted by @lacco in https://github.com/glebm/i18n-tasks/pull/95.
The code below is also available as a gem: https://github.com/halostatue/i18n-tasks-csv.
The first column contains the key. The second column contains the value in the base locale. The subsequent columns contain the values in the other locales (one column per locale). The first row of the CSV is the header row.
Example:
key | en | de |
---|---|---|
app.greeting | Hello | Hallo |
app.farewell | Goodbye | Tschüss |
Add CSV configuration to config/i18n-tasks.yml
:
# config/i18n-tasks.yml
<% require './lib/i18n_csv_tasks' %>
csv:
export:
- ["faqs.*", "tmp/i18n-export/faqs.csv"]
- "tmp/i18n-export/main.csv"
import:
- tmp/i18n-export/main.csv
- tmp/i18n-export/faqs.csv
Put implementation in lib/i18n_csv_tasks.rb
:
# lib/i18n_csv_tasks.rb
require 'i18n/tasks/commands'
require 'csv'
module I18nCsvTasks
include ::I18n::Tasks::Command::Collection
cmd :csv_export, desc: 'export translations to CSV'
def csv_export(opts = {})
translations_by_path = {}
router = I18n::Tasks::Data::Router::PatternRouter.new(nil, write: i18n.config["csv"]["export"])
i18n.locales.each do |locale|
router.route(locale, i18n.data_forest) do |path, nodes|
translations_by_path[path] ||= {}
translations_by_path[path][locale] ||= {}
nodes.leaves do |node|
translations_by_path[path][locale][node.full_key(root: false)] = node.value
end
end
end
translations_by_path.each do |(path, translations_by_locale)|
FileUtils.mkdir_p(File.dirname(path))
CSV.open(path, "wb") do |csv|
csv << (["key"] + i18n.locales)
translations_by_locale[i18n.base_locale].keys.each do |key|
values = i18n.locales.map do |locale|
translations_by_locale[locale][key]
end
csv << values.unshift(key)
end
end
end
end
cmd :csv_import, desc: 'import translations from CSV'
def csv_import(opts = {})
i18n.config["csv"]["import"].each do |file|
csv = open(file).read.force_encoding('UTF-8')
translations = []
CSV.parse(csv, headers: true) do |row|
key = row["key"]
next unless key
i18n.locales.each do |locale|
raise "Locale missing for key #{key}! (locales in app: #{locales} / locales in file: #{row.headers.inspect})" unless row.has_key?(locale)
translations << [[locale, key].join("."), row[locale]]
end
end
# # Uncomment this in order to attempt to recognise entries that are likely symbols pointing to
# # other translations, intended to be rendered in your .yml with a preceding colon:
# translations.map! { |t| [t.first, (t.last&.=~ /^(?=.*\.)[a-z0-9_\.]+$/) ? t.last.to_sym : t.last] }
i18n.data.merge! I18n::Tasks::Data::Tree::Siblings.from_flat_pairs(translations)
end
end
end
I18n::Tasks.add_commands I18nCsvTasks
$ i18n-tasks csv-import
$ i18n-tasks csv-export