55use Drupal \Component \Gettext \PoHeader ;
66use Drupal \Component \Gettext \PoItem ;
77use Drupal \Component \Gettext \PoStreamWriter ;
8+ use Drupal \Core \Language \LanguageManagerInterface ;
9+ use Drupal \itk_translation_extractor \Translation \Helper ;
10+ use Drupal \locale \PluralFormulaInterface ;
811use Symfony \Component \Translation \Dumper \PoFileDumper as BasePoFileDumper ;
912use Symfony \Component \Translation \Exception \InvalidArgumentException ;
1013use Symfony \Component \Translation \MessageCatalogue ;
1417 */
1518class PoFileDumper extends BasePoFileDumper
1619{
20+ public function __construct (
21+ private readonly LanguageManagerInterface $ languageManager ,
22+ private readonly PluralFormulaInterface $ pluralFormula ,
23+ ) {
24+ }
25+
1726 public function dump (MessageCatalogue $ messages , array $ options = []): void
1827 {
1928 if (!\array_key_exists ('path ' , $ options )) {
@@ -33,38 +42,38 @@ public function formatCatalogue(
3342 string $ domain ,
3443 array $ options = [],
3544 ): string {
45+ $ language = $ this ->languageManager ->getLanguage ($ messages ->getLocale ());
46+ if (!$ language ) {
47+ throw new InvalidArgumentException (sprintf ('Invalid locale: %s ' , $ messages ->getLocale ()));
48+ }
49+ $ pluralFormula = $ this ->pluralFormula ->getFormula ($ language ->getId ());
50+ $ numberOfPlurals = count ($ pluralFormula );
51+
3652 $ header = new PoHeader ();
37- // Set Plural-Forms
38- $ spec = '' ;
39- switch ($ messages ->getLocale ()) {
40- case 'da ' :
41- $ spec = 'Plural-Forms: nplurals=2; plural=(n != 1); ' ;
53+ if ($ pluralForm = $ this ->getPluralForm ($ messages ->getLocale ())) {
54+ // Set Plural-Forms
55+ $ header ->setFromString (sprintf ('Plural-Forms: %s; ' , $ pluralForm ));
4256 }
43- $ header ->setFromString ($ spec );
44- if ($ languageName = ($ options ['language_name ' ] ?? null )) {
45- $ header ->setLanguageName ($ languageName );
57+ if ($ language ) {
58+ $ header ->setLanguageName ($ language ->getName ());
4659 }
4760 if ($ projectName = ($ options ['project_name ' ] ?? null )) {
4861 $ header ->setProjectName ($ projectName );
4962 }
50- $ uri = tempnam (sys_get_temp_dir (), 'po_ ' );
5163
64+ $ uri = tempnam (sys_get_temp_dir (), 'po_ ' );
5265 $ writer = new PoStreamWriter ();
5366 $ writer ->setURI ($ uri );
5467 $ writer ->setHeader ($ header );
5568 $ writer ->open ();
5669 foreach ($ messages ->getDomains () as $ domain ) {
5770 foreach ($ messages ->all ($ domain ) as $ source => $ translation ) {
5871 $ metadata = $ messages ->getMetadata ($ source , $ domain );
59- // MessageCatalog has a special case for the empty domain.
60- if ('' === $ domain ) {
61- $ metadata = $ metadata [$ domain ][$ source ] ?? null ;
62- }
6372 $ item = new PoItem ();
73+ $ item ->setContext (Helper::getContext ($ domain ));
6474 if ($ plurals = ($ metadata ['plurals ' ] ?? null )) {
6575 $ item ->setPlural (true );
6676 $ item ->setSource ($ plurals );
67- // @todo!!!
6877 $ item ->setTranslation ($ plurals );
6978 } else {
7079 $ item ->setSource ($ source );
@@ -81,4 +90,99 @@ public function formatCatalogue(
8190
8291 return $ output ;
8392 }
93+
94+ public function getLanguageName (string $ langcode ): ?string
95+ {
96+ return self ::PLURAL_TABLE [$ langcode ][0 ] ?? null ;
97+ }
98+
99+ /**
100+ * Get plural form.
101+ */
102+ public function getPluralForm (string $ langcode ): ?string
103+ {
104+ return self ::PLURAL_TABLE [$ langcode ][1 ] ?? null ;
105+ }
106+
107+ // Lifted from
108+ // https://gitweb.git.savannah.gnu.org/gitweb/?p=gettext.git;a=blob;f=gettext-tools/src/plural-table.c;h=be87373a0aa59ef1eb04b0b1dba43dbb330f1afb;hb=HEAD
109+ // (found via
110+ // https://git.drupalcode.org/project/potx/-/blob/8.x-1.x/potx.inc?ref_type=heads#L655).
111+ private const array PLURAL_TABLE = [
112+ 'ja ' => ['Japanese ' , 'nplurals=1; plural=0; ' ],
113+ 'vi ' => ['Vietnamese ' , 'nplurals=1; plural=0; ' ],
114+ 'ko ' => ['Korean ' , 'nplurals=1; plural=0; ' ],
115+ 'en ' => ['English ' , 'nplurals=2; plural=(n != 1); ' ],
116+ 'de ' => ['German ' , 'nplurals=2; plural=(n != 1); ' ],
117+ 'nl ' => ['Dutch ' , 'nplurals=2; plural=(n != 1); ' ],
118+ 'sv ' => ['Swedish ' , 'nplurals=2; plural=(n != 1); ' ],
119+ 'da ' => ['Danish ' , 'nplurals=2; plural=(n != 1); ' ],
120+ 'no ' => ['Norwegian ' , 'nplurals=2; plural=(n != 1); ' ],
121+ 'nb ' => ['Norwegian Bokmal ' , 'nplurals=2; plural=(n != 1); ' ],
122+ 'nn ' => ['Norwegian Nynorsk ' , 'nplurals=2; plural=(n != 1); ' ],
123+ 'fo ' => ['Faroese ' , 'nplurals=2; plural=(n != 1); ' ],
124+ 'es ' => ['Spanish ' , 'nplurals=2; plural=(n != 1); ' ],
125+ 'pt ' => ['Portuguese ' , 'nplurals=2; plural=(n != 1); ' ],
126+ 'it ' => ['Italian ' , 'nplurals=2; plural=(n != 1); ' ],
127+ 'bg ' => ['Bulgarian ' , 'nplurals=2; plural=(n != 1); ' ],
128+ 'el ' => ['Greek ' , 'nplurals=2; plural=(n != 1); ' ],
129+ 'fi ' => ['Finnish ' , 'nplurals=2; plural=(n != 1); ' ],
130+ 'et ' => ['Estonian ' , 'nplurals=2; plural=(n != 1); ' ],
131+ 'he ' => ['Hebrew ' , 'nplurals=2; plural=(n != 1); ' ],
132+ 'eo ' => ['Esperanto ' , 'nplurals=2; plural=(n != 1); ' ],
133+ 'hu ' => ['Hungarian ' , 'nplurals=2; plural=(n != 1); ' ],
134+ 'tr ' => ['Turkish ' , 'nplurals=2; plural=(n != 1); ' ],
135+ 'ca ' => ['Catalan ' , 'nplurals=2; plural=(n != 1); ' ],
136+ 'pt_BR ' => ['Brazilian ' , 'nplurals=2; plural=(n > 1); ' ],
137+ 'fr ' => ['French ' , 'nplurals=2; plural=(n > 1); ' ],
138+ 'lv ' => [
139+ 'Latvian ' ,
140+ 'nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2); ' ,
141+ ],
142+ 'ga ' => ['Irish ' , 'nplurals=3; plural=n==1 ? 0 : n==2 ? 1 : 2; ' ],
143+ 'ro ' => [
144+ 'Romanian ' ,
145+ 'nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2; ' ,
146+ ],
147+ 'lt ' => [
148+ 'Lithuanian ' ,
149+ 'nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2); ' ,
150+ ],
151+ 'ru ' => [
152+ 'Russian ' ,
153+ 'nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); ' ,
154+ ],
155+ 'uk ' => [
156+ 'Ukrainian ' ,
157+ 'nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); ' ,
158+ ],
159+ 'be ' => [
160+ 'Belarusian ' ,
161+ 'nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); ' ,
162+ ],
163+ 'sr ' => [
164+ 'Serbian ' ,
165+ 'nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); ' ,
166+ ],
167+ 'hr ' => [
168+ 'Croatian ' ,
169+ 'nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); ' ,
170+ ],
171+ 'cs ' => [
172+ 'Czech ' ,
173+ 'nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2; ' ,
174+ ],
175+ 'sk ' => [
176+ 'Slovak ' ,
177+ 'nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2; ' ,
178+ ],
179+ 'pl ' => [
180+ 'Polish ' ,
181+ 'nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); ' ,
182+ ],
183+ 'sl ' => [
184+ 'Slovenian ' ,
185+ 'nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3); ' ,
186+ ],
187+ ];
84188}
0 commit comments