Brooklyn/plasma/workspace/applets/digital-clock/plugin/timezonesi18n_generate.rb

114 lines
4.0 KiB
Ruby
Raw Normal View History

2022-03-05 22:41:29 +05:00
#!/usr/bin/env ruby
# frozen_string_literal: true
# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
# SPDX-FileCopyrightText: 2021 Harald Sitter <sitter@kde.org>
# Generates timezone tables out of tzdata.zi backing data such that the pretty names may be translated.
require 'erb'
require 'ostruct'
# Wraps template rendering. Templating is implemented using the ERB template system.
class Template
def self.render(context)
erb = ERB.new(File.read("#{__dir__}/timezonesi18n_generated.h.erb"))
erb.result(context.instance_eval { binding })
end
end
# Context object for template rendering. Inside the template file anything defined in here may be used.
# For simplicity's sake continents and cities are not modeled as fully functional objects but rather use
# this context wrapper. Slightly less code.
class RenderContext < OpenStruct
def initialize(continents:, cities:)
super
end
def city_description(city)
return 'This is a generic time zone name, localize as needed' if city.start_with?('UTC')
'This is a city associated with particular time zone'
end
def continent_description(_continent)
'This is a continent/area associated with a particular timezone'
end
# prettify city name
def to_city_name(city)
city = city.tr('_', ' ')
{
'DumontDUrville' => 'Dumont dUrville',
'ComodRivadavia' => 'Comodoro Rivadavia'
# TODO do we want these? seeing as different transliterations are in use, one is just as bad as the other, surely
# 'Uzhgorod' => 'Uzhhorod' # the tz has the legacy transliteration
# 'Zaporozhye' => 'Zaporizhzhia'
# 'Kiev' => 'Kyiv'
}.fetch(city, city)
end
# prettify continent name
def to_contient_name(continent)
continent # leave unchanged, they are all lovely
end
end
raise 'tzdata.zi missing, your tzdata was possibly built without' unless File.exist?('/usr/share/zoneinfo/tzdata.zi')
data = File.read('/usr/share/zoneinfo/tzdata.zi')
continents = []
cities = []
data.split("\n").each do |line|
line = line.strip
next if line[0] == '#' # comment
# zi files have a tricky format. only look at lines that make sense for us (Zone entries and Link entries)
is_zone = line[0].downcase == 'z'
is_link = line[0].downcase == 'l'
next unless is_zone || is_link
line_parts = line.split(' ')
# Since we have 2 line formats, the location of the timezone is different in each
tz = is_zone ? line_parts[1] : line_parts[2]
parts = tz.split('/')
# some links are fishy single names we can't use (e.g. `L Europe/Warsaw Poland`)
next if parts.size < 2
continent = parts[0]
# some links also have fake continent values (e.g. `L America/Denver SystemV/MST7MDT`) followed by regions therein
next if %w[systemv us etc canada brazil mexico chile].any? { |x| x == continent.downcase }
city = parts[-1]
# some links are simply pointing at directions within a region/country
next if %w[north east south west].any? { |x| x == city.downcase }
# some links are abbreviations (e.g. `Australia/NSW` for new south wales)
# Australia has some more links for regions but we'd have to filter them individually and I can't be bothered.
next if city.size <= 3 && city.upcase == city
# some are Knox and also known as Knox_IN for reasons
next if city == 'Knox_IN'
continents << continent
cities << city
end
# make sure fake cities exist
(0..14).each do |i|
cities << format('UTC+%02d:00', i)
cities << format('UTC-%02d:00', i)
end
# The partial hours are from original code this script was built based on. They do not actually correspond to timezone
# links though, so I'm not sure how they work but keep them regardless since I hope there's magic going on somehwere.
cities += %w[UTC UTC+03:30 UTC+04:30 UTC+05:30 UTC+05:45 UTC+06:30 UTC+09:30 UTC-03:30 UTC-04:30]
cities = cities.sort_by(&:downcase).uniq
continents = continents.sort_by(&:downcase).uniq
data = Template.render(RenderContext.new(cities: cities, continents: continents))
File.write("#{__dir__}/timezonesi18n_generated.h", data)