From 17e858cc9a250d3fe779177fa7305de2ea3fadf5 Mon Sep 17 00:00:00 2001 From: Michael Overmeyer Date: Thu, 9 Dec 2021 10:44:34 -0500 Subject: [PATCH] Clean up locale fallback code It was breaking on locales with more than two segments (e.g., `zh-Hant-HK`) Beyond that, I pulled out the fallback code and exposed it so that downstream consumers can use it too. I structured it in a similar manner as `ruby-i18n`'s [`I18n::Locale::Fallbacks`](https://github.com/ruby-i18n/i18n/blob/535459ad1201e7cc97a071bd5d9f0e1d5406069e/lib/i18n/locale/fallbacks.rb). I also changed the keys and values in `ParentLocales` to be symbols, which simplifies the code. It's still not fully correct for locales that contain scripts (e.g., `ff-Adlm-GH`). That will be a different commit. --- CHANGELOG.md | 2 ++ lib/cldr.rb | 9 ++++++++- lib/cldr/export.rb | 19 +++---------------- lib/cldr/export/data/parent_locales.rb | 4 ++-- lib/cldr/locale.rb | 7 +++++++ lib/cldr/locale/fallbacks.rb | 22 ++++++++++++++++++++++ ruby-cldr.gemspec | 3 +++ test/locale/fallbacks_test.rb | 18 ++++++++++++++++++ 8 files changed, 65 insertions(+), 19 deletions(-) create mode 100644 lib/cldr/locale.rb create mode 100644 lib/cldr/locale/fallbacks.rb create mode 100644 test/locale/fallbacks_test.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f20c79a..1273f28d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Sort the exported data by key, [#82](https://github.com/ruby-i18n/ruby-cldr/pull/82) - Prune empty hashes / files before outputting, [#86](https://github.com/ruby-i18n/ruby-cldr/pull/86) - Re-add the `ParentLocales` component, this time as a shared component, [#91](https://github.com/ruby-i18n/ruby-cldr/pull/91) +- Changed the keys and values of `ParentLocales` component to be symbols, [#101](https://github.com/ruby-i18n/ruby-cldr/pull/101) +- Fixed bug with fallbacks for locales that had more than two segments, [#101](https://github.com/ruby-i18n/ruby-cldr/pull/101) --- diff --git a/lib/cldr.rb b/lib/cldr.rb index a1f4b1c5..a5a95d21 100644 --- a/lib/cldr.rb +++ b/lib/cldr.rb @@ -3,5 +3,12 @@ module Cldr autoload :Data, 'cldr/data' autoload :Export, 'cldr/export' + autoload :Locale, 'cldr/locale' autoload :Format, 'cldr/format' -end \ No newline at end of file + + class << self + def fallbacks + @@fallbacks ||= Cldr::Locale::Fallbacks.new + end + end +end diff --git a/lib/cldr/export.rb b/lib/cldr/export.rb index 0ee70e0d..367685eb 100644 --- a/lib/cldr/export.rb +++ b/lib/cldr/export.rb @@ -135,25 +135,12 @@ def locales(locale, component, options) locale = to_i18n(locale) locales = if options[:merge] - defined_parents = Cldr::Export::Data::ParentLocales.new - - ancestry = [locale.to_s] - loop do - if defined_parents[ancestry.last] - ancestry << defined_parents[ancestry.last] - elsif I18n::Locale::Tag.tag(ancestry.last).self_and_parents.count > 1 - ancestry << I18n::Locale::Tag.tag(ancestry.last).self_and_parents.last - else - break - end - end - - ancestry.map(&:to_sym) + Cldr.fallbacks[locale] else - [locale] + [locale, :root] end - locales << :root if should_merge_root?(locale, component, options) + locales.pop unless should_merge_root?(locale, component, options) locales end diff --git a/lib/cldr/export/data/parent_locales.rb b/lib/cldr/export/data/parent_locales.rb index caf36d96..ec68d653 100644 --- a/lib/cldr/export/data/parent_locales.rb +++ b/lib/cldr/export/data/parent_locales.rb @@ -9,8 +9,8 @@ def initialize(_ = nil) doc = File.open(path) { |file| Nokogiri::XML(file) } doc.xpath('//parentLocales/parentLocale').each do |node| - parent = Cldr::Export.to_i18n(node.attr('parent')).to_s - locales = node.attr('locales').split(' ').map {|locale| Cldr::Export.to_i18n(locale) }.map(&:to_s) + parent = Cldr::Export.to_i18n(node.attr('parent')) + locales = node.attr('locales').split(' ').map {|locale| Cldr::Export.to_i18n(locale) } locales.each do |locale| self[locale] = parent diff --git a/lib/cldr/locale.rb b/lib/cldr/locale.rb new file mode 100644 index 00000000..04488af3 --- /dev/null +++ b/lib/cldr/locale.rb @@ -0,0 +1,7 @@ +# encoding: utf-8 + +module Cldr + module Locale + autoload :Fallbacks, 'cldr/locale/fallbacks' + end +end diff --git a/lib/cldr/locale/fallbacks.rb b/lib/cldr/locale/fallbacks.rb new file mode 100644 index 00000000..2410adf6 --- /dev/null +++ b/lib/cldr/locale/fallbacks.rb @@ -0,0 +1,22 @@ +module Cldr + module Locale + class Fallbacks < Hash + def [](locale) + defined_parents = Cldr::Export::Data::ParentLocales.new + + ancestry = [locale] + loop do + if defined_parents[ancestry.last] + ancestry << defined_parents[ancestry.last] + elsif I18n::Locale::Tag.tag(ancestry.last).parents.count > 0 + ancestry << I18n::Locale::Tag.tag(ancestry.last).parents.first.to_sym + else + break + end + end + ancestry << :root unless ancestry.last == :root + store(locale, ancestry) + end + end + end +end diff --git a/ruby-cldr.gemspec b/ruby-cldr.gemspec index d50ebe45..e784d078 100644 --- a/ruby-cldr.gemspec +++ b/ruby-cldr.gemspec @@ -82,6 +82,8 @@ Gem::Specification.new do |s| "lib/cldr/format/decimal/number.rb", "lib/cldr/format/percent.rb", "lib/cldr/format/time.rb", + "lib/cldr/locale.rb", + "lib/cldr/locale/fallbacks.rb", "lib/cldr/thor.rb", "lib/core_ext/hash/deep_merge.rb", "lib/core_ext/hash/deep_prune.rb", @@ -118,6 +120,7 @@ Gem::Specification.new do |s| "test/format/decimal_test.rb", "test/format/percent_test.rb", "test/format/time_test.rb", + "test/locale/fallbacks_test.rb", "test/test_autotest.rb", "test/test_helper.rb" ] diff --git a/test/locale/fallbacks_test.rb b/test/locale/fallbacks_test.rb new file mode 100644 index 00000000..82c0e84d --- /dev/null +++ b/test/locale/fallbacks_test.rb @@ -0,0 +1,18 @@ +# encoding: utf-8 + +require File.expand_path(File.join(File.dirname(__FILE__) + '/../test_helper')) + +class TestFallbacks < Test::Unit::TestCase + test "fallbacks does basic hyphen chopping" do + assert_equal [:root], Cldr.fallbacks[:root] + assert_equal [:en, :root], Cldr.fallbacks[:en] + assert_equal [:"fr-CA", :fr, :root], Cldr.fallbacks[:"fr-CA"] + assert_equal [:"zh-Hant-HK", :"zh-Hant", :root], Cldr.fallbacks[:"zh-Hant-HK"] + end + + test "fallbacks observe explicit parent overrides" do + assert_equal [:"az-Arab", :root], Cldr.fallbacks[:"az-Arab"] + assert_equal [:"en-CH", :"en-150", :"en-001", :en, :root], Cldr.fallbacks[:"en-CH"] + assert_equal [:"zh-Hant", :root], Cldr.fallbacks[:"zh-Hant"] + end +end