@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fix calculation of "limited translations" to not include en_US fallback

Summary:
Broken by me in D25695 last year. Sigh, I really wasn't on my A game then.

And also mark locales with zero translations (like "English (Canada)" which doesn't have an upstream translations file) as limited too even if they are varieties of English.

Depends on D26559 to work.

Test Plan:
With the downstream translation extension installed, see more languages (like "Asturian") in "Limited Translations" on http://phorge.localhost/settings/panel/language/. Note that this section is only shown in developer mode (http://phorge.localhost/config/edit/phabricator.developer-mode/ resp `./bin/config set phabricator.developer-mode true`).

With the downstream translation extension installed, see "Tarantino" not in Limited Translations (it has < 512 strings by itself but >512 strings if you count the Italian fallback)

Without the downstream translation extension installed, see all of the locales upstream in "Limited Translations".

With or without the downstream translation extension installed (translatewiki.net doesn't support en-CA), see "English (Canada)" in "Limited Translations".

Reviewers: O1 Blessed Committers, aklapper

Reviewed By: O1 Blessed Committers, aklapper

Subscribers: aklapper, avivey, tobiaswiese, valerio.bozzolan, Matthew, Cigaryno

Differential Revision: https://we.phorge.it/D26560

Pppery 4067d98a 7ac05c4e

+87 -39
+87 -39
src/applications/settings/setting/PhabricatorTranslationSetting.php
··· 32 32 } 33 33 34 34 protected function getSelectOptionGroups() { 35 - $locales = PhutilLocale::loadAllLocales(); 35 + // Loading translations for all locales and determining 36 + // whether they are limited can be expensive so cache it 37 + $cache = PhabricatorCaches::getRuntimeCache(); 38 + $groups = $cache->getKey('locale.groups'); 39 + if (!$groups) { 40 + $groups = $this->getLocaleGroups(); 41 + $cache->setKey('locale.groups', $groups); 42 + } 36 43 44 + // These are done after the cache check so that changes to these config 45 + // settings via the web UI apply immediately 46 + 47 + // Omit silly locales on serious business installs. 48 + $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); 49 + if ($is_serious) { 50 + unset($groups['silly']); 51 + } 52 + 53 + // Omit limited and test translations if Phabricator is not in developer 54 + // mode. 55 + $is_dev = PhabricatorEnv::getEnvConfig('phabricator.developer-mode'); 56 + if (!$is_dev) { 57 + unset($groups['limited']); 58 + unset($groups['test']); 59 + } 60 + 61 + // This can't be in the cache since these pht calls 62 + // evaluate based on the locale of the current user 37 63 $group_labels = array( 38 64 'normal' => pht('Translations'), 39 65 'limited' => pht('Limited Translations'), 40 66 'silly' => pht('Silly Translations'), 41 67 'test' => pht('Developer/Test Translations'), 42 68 ); 69 + $results = array(); 70 + foreach ($groups as $key => $group) { 71 + $label = $group_labels[$key]; 72 + if (!$group) { 73 + continue; 74 + } 43 75 44 - $groups = array_fill_keys(array_keys($group_labels), array()); 76 + asort($group); 45 77 46 - $translations = array(); 78 + $results[] = array( 79 + 'label' => $label, 80 + 'options' => $group, 81 + ); 82 + } 83 + 84 + return $results; 85 + } 86 + 87 + private function getLocaleGroups() { 88 + $groups = array( 89 + 'normal' => array(), 90 + 'limited' => array(), 91 + 'silly' => array(), 92 + 'test' => array(), 93 + ); 94 + $translations = PhutilTranslation::getAllTranslations(); 95 + $locales = PhutilLocale::loadAllLocales(); 47 96 foreach ($locales as $locale) { 48 97 $code = $locale->getLocaleCode(); 49 98 50 99 // Get the locale's localized name if it's available. For example, 51 100 // "Deutsch" instead of "German". This helps users who do not speak the 52 101 // current language to find the correct setting. 102 + // This also means that the locale name can be cached as it doesn't 103 + // vary on user settings. 53 104 $raw_scope = PhabricatorEnv::beginScopedLocale($code); 54 105 $name = $locale->getLocaleName(); 55 106 unset($raw_scope); ··· 64 115 continue; 65 116 } 66 117 67 - $strings = PhutilTranslation::getTranslationMapForLocale($code); 68 - $size = count($strings); 118 + if (empty($translations[$code])) { 119 + // Locales with zero translations are always "limited" 120 + // even if they are English, even if the fallback has some 121 + // (silly locales that post-process text rather than translating 122 + // like "ENGLISH (ALL CAPS)" are handled above) 123 + $groups['limited'][$code] = $name; 124 + continue; 125 + } 69 126 70 127 // If a translation is English, assume it can fall back to the default 71 128 // strings and don't caveat its completeness. 72 - $is_english = (substr($code, 0, 3) == 'en_'); 129 + if (substr($code, 0, 3) == 'en_') { 130 + $groups['normal'][$code] = $name; 131 + continue; 132 + } 73 133 74 134 // Arbitrarily pick some number of available strings to promote a 75 135 // translation out of the "limited" group. The major goal is just to 76 136 // keep locales with very few strings out of the main group, so users 77 137 // aren't surprised if a locale has no upstream translations available. 78 - if ($size > 512 || $is_english) { 138 + $limited_max = 512; 139 + 140 + // Grab all fallbacks except the default fallback to en_US 141 + $current = $code; 142 + $strings = array(); 143 + while ($current && $current != 'en_US') { 144 + $strings += $translations[$current]; 145 + $fallbacks = $locales[$current]->getFallbackLocaleCode(); 146 + if (is_array($fallbacks)) { 147 + foreach ($fallbacks as $fb) { 148 + if ($fb != 'en_US' && isset($translations[$fb])) { 149 + $strings += $translations[$fb]; 150 + } 151 + } 152 + break; 153 + } 154 + $current = $fallbacks; 155 + } 156 + 157 + if (count($strings) > $limited_max) { 79 158 $type = 'normal'; 80 159 } else { 81 160 $type = 'limited'; ··· 83 162 84 163 $groups[$type][$code] = $name; 85 164 } 86 - 87 - // Omit silly locales on serious business installs. 88 - $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); 89 - if ($is_serious) { 90 - unset($groups['silly']); 91 - } 92 - 93 - // Omit limited and test translations if Phabricator is not in developer 94 - // mode. 95 - $is_dev = PhabricatorEnv::getEnvConfig('phabricator.developer-mode'); 96 - if (!$is_dev) { 97 - unset($groups['limited']); 98 - unset($groups['test']); 99 - } 100 - 101 - $results = array(); 102 - foreach ($groups as $key => $group) { 103 - $label = $group_labels[$key]; 104 - if (!$group) { 105 - continue; 106 - } 107 - 108 - asort($group); 109 - 110 - $results[] = array( 111 - 'label' => $label, 112 - 'options' => $group, 113 - ); 114 - } 115 - 116 - return $results; 165 + return $groups; 117 166 } 118 - 119 167 }