From d20d079ff8ca2ed8071c3514b3366a7215cdc205 Mon Sep 17 00:00:00 2001 From: Wadim Wawrzenczak Date: Mon, 17 Feb 2025 17:16:42 +0100 Subject: [PATCH] (ilib-loctool-tap-i18n) Always output plural category `many` for Polish and Russian targets --- .changeset/rich-humans-wonder.md | 5 ++ packages/ilib-loctool-tap-i18n/YamlFile.js | 40 +++++++++++- .../test/YamlFile.test.js | 62 +++++++++++++++++++ 3 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 .changeset/rich-humans-wonder.md diff --git a/.changeset/rich-humans-wonder.md b/.changeset/rich-humans-wonder.md new file mode 100644 index 000000000..3b0b16466 --- /dev/null +++ b/.changeset/rich-humans-wonder.md @@ -0,0 +1,5 @@ +--- +"ilib-loctool-tap-i18n": patch +--- + +Fixed plural categories in plugin output to always produce required category `many` for Polish and Russian. diff --git a/packages/ilib-loctool-tap-i18n/YamlFile.js b/packages/ilib-loctool-tap-i18n/YamlFile.js index e2df03bf7..a79e2ad5c 100644 --- a/packages/ilib-loctool-tap-i18n/YamlFile.js +++ b/packages/ilib-loctool-tap-i18n/YamlFile.js @@ -377,6 +377,20 @@ YamlFile.prototype.convertToToolsResource = function(resource) { } }; +/** + * Additional plural categories required for specified languages. + * + * @type {Map>} + */ +var requiredPluralCategories = new Map([ + ["pl", [ + "many" + ]], + ["ru", [ + "many" + ]] +]); + /** * Generate the content of the resource file. * @@ -396,8 +410,28 @@ YamlFile.prototype.getContent = function(set) { if (resource.getType() === "plural") { var sourcePlurals = resource.getSourcePlurals(); var targetPlurals = resource.getTargetPlurals(); - var pluralCategories = Object.keys(targetPlurals || sourcePlurals).sort(); - pluralCategories.forEach(function(category) { + + // accumulate all plural categories which should be present in the output file: + // 0. every plural must have at least the "other" category + // 1a. categories from the target plural - translation should be provided for every category + // required in the target language + // 1b. fallback to categories from the source plural in case no translations were provided + // 2. categories required for the target language - some languages may require specific categories + // to be present in the output file even if they were not provided in translation + // (in this case the translation from "other" plural category will be used as a fallback) + var pluralCategories = new Set(["other"]); + Object.keys(targetPlurals || sourcePlurals).forEach(function (category) { + pluralCategories.add(category); + }); + var language = new Locale(resource.getTargetLocale()).getLanguage(); + var additionalCategories = requiredPluralCategories.get(language); + if (additionalCategories) { + additionalCategories.forEach(function (category) { + pluralCategories.add(category); + }); + } + + Array.from(pluralCategories).sort().forEach(function(category) { var newres = new tools.ResourceString({ key: resource.getKey() + "_" + category, sourceLocale: resource.getSourceLocale(), @@ -411,7 +445,7 @@ YamlFile.prototype.getContent = function(set) { state: "new" }); if (targetPlurals) { - newres.setTarget(targetPlurals[category]); + newres.setTarget(targetPlurals[category] ?? targetPlurals.other); newres.setTargetLocale(resource.getTargetLocale()); } filtered.add(newres); diff --git a/packages/ilib-loctool-tap-i18n/test/YamlFile.test.js b/packages/ilib-loctool-tap-i18n/test/YamlFile.test.js index 9b30b2081..138a39d5b 100644 --- a/packages/ilib-loctool-tap-i18n/test/YamlFile.test.js +++ b/packages/ilib-loctool-tap-i18n/test/YamlFile.test.js @@ -1400,6 +1400,7 @@ describe("yamlfile", function() { targetStrings: { one: "Jest {n} pozycja.", few: "Jest {n} pozycje.", + many: "Jest {n} pozycji.", other: "Jest {n} pozycji." }, targetLocale: "pl-PL", @@ -1410,6 +1411,67 @@ describe("yamlfile", function() { var expected = 'thanked_note_time_saved:\n' + ' email_subject_few: Jest {n} pozycje.\n' + + ' email_subject_many: Jest {n} pozycji.\n' + + ' email_subject_one: Jest {n} pozycja.\n' + + ' email_subject_other: Jest {n} pozycji.\n'; + diff(actual, expected); + expect(actual).toBe(expected); + }); + + test("YamlFile localize text with plurals and filling a missing required plural category", function() { + expect.assertions(7); + var yml = new YamlFile({ + project: p, + type: yft + }); + expect(yml).toBeTruthy(); + yml.parse( + 'thanked_note_time_saved:\n' + + ' email_subject_one: There is {n} item.\n' + + ' email_subject_other: There are {n} items.\n' + ); + var set = yml.getTranslationSet("en-US"); + expect(set).toBeTruthy(); + var resources = set.getAll(); + expect(resources.length).toBe(1); + + var r = resources[0]; + expect(r).toBeTruthy(); + expect(r.getType()).toBe("plural"); + + expect(r.getSourcePlurals()).toStrictEqual({ + one: "There is {n} item.", + other: "There are {n} items." + }); + + var translations = new TranslationSet("en-US"); + translations.add( + new ResourcePlural({ + project: "webapp", + key: 'thanked_note_time_saved.email_subject', + sourceStrings: { + one: "There is {n} item.", + other: "There are {n} items." + }, + sourceLocale: "en-US", + targetStrings: { + one: "Jest {n} pozycja.", + few: "Jest {n} pozycje.", + // translation for "many" is missing + // but it is required by tap-i18n library for Polish + other: "Jest {n} pozycji." + }, + targetLocale: "pl-PL", + datatype: "x-yaml" + }) + ); + var actual = yml.localizeText(translations, "pl-PL"); + var expected = + 'thanked_note_time_saved:\n' + + ' email_subject_few: Jest {n} pozycje.\n' + + // "many" is present in the ouput and + // its value matches the value of "other" + ' email_subject_many: Jest {n} pozycji.\n' + ' email_subject_one: Jest {n} pozycja.\n' + ' email_subject_other: Jest {n} pozycji.\n'; diff(actual, expected);