typeofweb / polish-plurals

Package for generating correct plurals in Polish.
https://typeofweb.com/2018/01/22/odmiana-rzeczownikow-przy-liczebnikach-jezyku-polskim/
57 stars 2 forks source link

Dzięki super paczka #10

Open gustawdaniel opened 4 years ago

gustawdaniel commented 4 years ago

Właśnie sprawdzam jak to można wykorzystać w integracji z Vue

https://phrase.com/blog/posts/ultimate-guide-to-vue-localization-with-vue-i18n/#Custom_Pluralization

gustawdaniel commented 4 years ago

Jak ktoś w przyszłości będzie potrzebował to załączam fragment kodu


let defaultChoiceIndex;

export function setDefaultChoiceIndexGet(fn) {
  defaultChoiceIndex = fn
}

/**
 * @param choice {number} a choice index given by the input to
 *   $tc: `$tc('path.to.rule', choiceIndex)`
 * @param choicesLength {number} an overall amount of available choices
 * @returns number - a final choice index to select plural word by
 **/
export function getChoiceIndex(choice, choicesLength) {
  if (defaultChoiceIndex === undefined) {
    return choice
  }

  // this === VueI18n instance, so the locale property also exists here
  if (this.locale !== "pl") {
    return defaultChoiceIndex.apply(this, [choice, choicesLength])
  }

  if (1 === choice) {
    return 0 // "komentarz"
  }

  if (choice % 10 >= 2 && choice % 10 <= 4 && (choice % 100 < 10 || choice % 100 >= 20)) {
    return 1 // eg. "komentarze"
  }

  return 2 // eg. "komentarzy"
}

Jeszcze raz dzięki za kluczowy warunek logiczny :)

skix123 commented 4 years ago

Niestety warunek choice % 100 < 10 || choice % 100 >= 20 jest niepoprawny zgodnie z https://unicode-org.github.io/cldr-staging/charts/37/supplemental/language_plural_rules.html#pl

Modulo 100 musi być różne niż 12, 13 i 14.

A więc:

if ([0, 1].includes(choice)) return choice;
const mod10: number = choice % 10;
const mod100: number = choice % 100;
if ([2, 3, 4].includes(mod10) && ![12, 13, 14].includes(mod100)) return 2;
return 3;

^ wersja pod Vue z 4 opcjami: "people": "Nikogo tu nie ma | Tylko {n} osoba | {n} osoby | {n} osób" {{ $tc('people', peopleCount) }}

To i tak tylko dla liczb całkowitych, na wymierne powinien być sprawdzany jeszcze dodatkowy warunek.

typeofweb commented 4 years ago

@skix123 czy możesz podać przykład, w którym kod z tej paczki zawodzi? https://github.com/mmiszy/polish-plurals/blob/5d2dc0cdea93e68e0a320a0201f0acb7a53206d0/index.mjs#L5

typeofweb commented 4 years ago

@skix123 przeprowadziłem następujący test:

function polishPlurals1(singularNominativ, pluralNominativ, pluralGenitive, value) {
  value = Math.abs(value);
  if (value === 1) {
      return singularNominativ;
  } else if (value % 10 >= 2 && value % 10 <= 4 && (value % 100 < 10 || value % 100 >= 20)) {
      return pluralNominativ;
  } else {
      return pluralGenitive;
  }
}

function polishPlurals2(singularNominativ, pluralNominativ, pluralGenitive, value) {
  value = Math.abs(value);
  const mod10 = value % 10;
  const mod100 = value % 100;
  if (value === 1) {
      return singularNominativ;
  } else if ([2,3,4].includes(mod10) && ![12,13,14].includes(mod100)) {
      return pluralNominativ;
  } else {
      return pluralGenitive;
  }
}

polishPlurals1 to oryginalna implementacja, a polishPlurals2 to ta sugerowana przez Ciebie. Okazuje się, że obie zwracają dokładnie to samo dla dowolnych liczb :)

for (let i = 0; i < 1000000; ++i) {
  console.assert(
    polishPlurals1("komentarz", "komentarze", "komentarzy", i)
    ===
    polishPlurals2("komentarz", "komentarze", "komentarzy", i)
  )
}
// brak błędów
skix123 commented 4 years ago

Ciekawe, zatem sory za wprowadzenie w błąd