ruby-gettext / gettext

Gettext gem is a pure Ruby Localization(L10n) library and tool which is modeled after the GNU gettext package.
https://ruby-gettext.github.io/
69 stars 28 forks source link

Locale fallback if missing translation (ex: `en_US` => `en`) #89

Closed MichaelHoste closed 2 years ago

MichaelHoste commented 2 years ago

I was wondering if GetText has already some existing mechanism to deal with locale fallbacks.

It would be really useful for regional languages (like en_US) so we could avoid duplicating, and co-evolving, most translations that are the same.

In a project where fr is the source language and en and en_US are the target languages, it would be nice if a missing translation to en_US would fallback to en before fallbacking to fr (current behaviour).

I did a quick ugly hack in text_domain.rb (translate_singular_message) and it seems to work well for me:

I replaced

return mo[msgid] if mo.has_key?(msgid)

by

if mo.has_key?(msgid)
  return mo[msgid]
elsif lang.to_s.include?('_')
  new_lang = Locale::Tag.parse(lang.to_s.split('_').first) #  yes, ugly for now...
  return translate_singular_message(new_lang, msgid)
end

If I implement this solution correctly, would you consider merging it @kou ? Or are there any existing alternative?

kou commented 2 years ago

If I implement this solution correctly, would you consider merging it?

Sure.

I think that we should do this in TextDomainManager not TextDomain.

I haven't tried it but this may work:

diff --git a/lib/gettext/text_domain_manager.rb b/lib/gettext/text_domain_manager.rb
index e329fb4..c4ced0c 100644
--- a/lib/gettext/text_domain_manager.rb
+++ b/lib/gettext/text_domain_manager.rb
@@ -77,11 +77,12 @@ module GetText
     end

     def each_text_domains(klass) #:nodoc:
-      lang = Locale.candidates[0]
-      ClassInfo.related_classes(klass, @@gettext_classes).each do |target|
-        if group = @@text_domain_group_pool[target]
-          group.text_domains.each do |text_domain|
-            yield text_domain, lang
+      Locale.candidates.each do |lang|
+        ClassInfo.related_classes(klass, @@gettext_classes).each do |target|
+          if group = @@text_domain_group_pool[target]
+            group.text_domains.each do |text_domain|
+              yield text_domain, lang
+            end
           end
         end
       end
MichaelHoste commented 2 years ago

Thanks a lot for your suggestion @kou !

I'll create a new PR for this in the following weeks with some tests.

MichaelHoste commented 2 years ago

I finally created the PR here: #90

The suggested implementation worked great!

MichaelHoste commented 2 years ago

The PR was merged and released, I guess we can close this issue now.