=== PlugForge Transliteration Standards ===
Contributors: plugforge
Tags: transliteration, cyrillic, slug, woocommerce, ukrainian
Requires at least: 6.2
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 0.1.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Transliterates new slugs and file names using documented national, UN and BGN/PCGN romanisation standards.

== Description ==

Cyrillic, Greek, Georgian or Armenian in a URL gets percent-encoded, and a link
that reads `%d0%ba%d0%b8%d1%97%d0%b2` is no use to anyone. Transliteration
fixes that. The question is which Latin letters to use, and tables written so
the Latin can be turned back into the original produce addresses no one would
type, such as `shhastya` or `czokol`.

PlugForge Transliteration Standards uses the romanisation standards that countries and the
United Nations publish: a resolution of Ukraine's Cabinet of Ministers,
Bulgaria's Transliteration Act, Georgia's national system and others. Some of
them change a letter by its place in the word. Bulgarian ия is ia at the end of
a word and iya inside one, and the plugin follows rules like that as written.

Nothing changes until you choose a standard for a language.

= Features =

* 13 standards for 11 languages, each linked to its source document.
* New posts, pages, terms, products and uploaded files get readable addresses.
* Exceptions for brand names and established spellings, as whole words or
  whole phrases.
* The language of each post with Polylang.
* A report of what your existing post slugs would become, with a CSV download.
* Nothing loaded on the public site, and no outbound requests.

= Supported standards =

* **Ukrainian**: Resolution no. 55 of the Cabinet of Ministers, 27 January
  2010. Київ → `kyiv`. All 76 worked examples in its annex come out exactly.
  <https://zakon.rada.gov.ua/laws/show/55-2010-п>
* **Russian**: Three standards, because Russian has three and they disagree.
  Pick the one your paperwork names. ICAO Doc 9303, what a Russian passport
  uses: Южно → `iuzhno`. BGN/PCGN 1947, what English-language publishing uses:
  Южно → `yuzhno`. ГОСТ 7.79-2000 system B, the reversible scheme described
  above, for matching addresses your site already has: Цоколь → `czokol`.
  <https://www.icao.int/sites/default/files/publications/DocSeries/9303_p3_cons_en.pdf>
* **Bulgarian**: The Transliteration Act of 2009, an act of parliament.
  София → `sofia`.
  <https://www.mrrb.bg/static/media/ups/articles/attachments/TRANSLITERATION%20ACT48938c89238d30492f9d6456d4b8ee7e.pdf>
* **Serbian**: The United Nations system of 1977, which is Gaj's Latin
  alphabet. Шабац → `sabac`. <https://arhiiv.eki.ee/wgrs/rom1_sr.htm>
* **Macedonian**: The United Nations system of 1977. Ќесендре → `kesendre`.
  <https://arhiiv.eki.ee/wgrs/rom1_mk.htm>
* **Belarusian**: The United Nations system of 2012, based on the national
  łacinka of 2007. Віцебск → `viciebsk`. <https://arhiiv.eki.ee/wgrs/rom1_be.htm>
* **Greek**: ELOT 743, what Greece prints on passports and road signs.
  Άγγελος → `angelos`. <https://arhiiv.eki.ee/wgrs/rom1_el.htm>
* **Georgian**: The national system of 2002, approved by presidential decree
  in 2011. თბილისი → `tbilisi`.
  <https://matsne.gov.ge/ka/document/view/1216954?publication=0>
* **Kazakh**: BGN/PCGN 1979, for Kazakh written in Cyrillic. Kazakhstan
  publishes no romanisation of its own. Қызылорда → `qyzylorda`.
* **Armenian**: BGN/PCGN 1981, for eastern Armenian. Երևան → `yerevan`.
  <https://assets.publishing.service.gov.uk/media/636cd40ad3bf7f164de3c9f3/ROMANIZATION_OF_ARMENIAN_2022_final.pdf>
* **Mongolian**: MNS 5217:2012, Mongolia's own standard. Улаанбаатар →
  `ulaanbaatar`.

An address keeps plain letters only. WordPress folds diacritics away, so
Serbian Ћирилица and Чирилица both end up as `cirilica`, and the apostrophes
the Georgian and Armenian standards write are dropped.

= Existing URLs =

Installing the plugin changes no existing address.

The "What would change" screen lists your existing posts whose slug does not
match the standard you chose, with the address each has now, the address it
would get and the language of the post. A row that would collide with another
is marked and left for you to resolve by hand. Reading the list or downloading
it as a CSV changes nothing.

A button under the list rewrites the posts on that page, after you tick a box
to confirm. WordPress keeps each old post slug and redirects it to the new one,
so links already published go on working.

Pages, categories, tags and media files already on your site are never
converted. WordPress keeps no record of their old addresses, so nothing would
redirect them.

= Exceptions =

Whole words and whole phrases for brand names and for spellings someone's
passport already carries. One per line: the word or phrase, an equals sign,
what it becomes.

    вордпрес = wordpress
    Жуковський = Zhukovsky

Matching ignores case, and spaces, hyphens and underscores between words count
as the same join. Only whole words are replaced. Digits and symbols that belong
to a name, as in Формула 1 or AT&T, have to be written as they appear.

= Multilingual sites =

On a site with one language, the standard follows the site language. With
Polylang, it follows the language set on each post or term, so two posts in the
same admin can go through two different standards. On such a site, a slug that
carries no language, such as one created by WP-CLI, is left alone.

The language is never guessed from the text: Гора is `hora` in Ukrainian and
`gora` in Russian, and the letters are identical.

WPML is not supported, because it has not been tested with this plugin.

= WooCommerce =

Tested with WooCommerce 11. New product slugs, product categories and tags,
shipping classes, attribute names and terms, downloadable files and product
images are all transliterated. Coupon codes are left alone, because customers
type them and codes already printed have to go on working. So is the product
permalink base, which you set yourself.

= Privacy and performance =

* No outbound requests: no update server of its own, no licence check, no usage
  statistics.
* No background jobs. A conversion you start runs while you watch it.
* No stylesheet and no script on any public page.
* Files already uploaded are never renamed.
* One dashboard notice, for administrators, and only if the PHP mbstring
  extension is missing.

= For developers =

* `translit_standards_language`: The language code to transliterate by. Return
  an empty string to leave a string alone.
* `translit_standards_result`: The transliterated string, with the text the
  engine was given and the standard key.
* `translit_standards_site_languages`: The language codes the settings screen
  offers a row for.

== Installation ==

1. Install and activate PlugForge Transliteration Standards.
2. Go to Settings > PlugForge Transliteration Standards.
3. Choose a standard for each language your site writes in. None is selected on
   install, and a language you leave alone stays untouched.
4. Add exceptions if you need them.
5. Open "What would change" to see what your existing post slugs would become.

The plugin needs the PHP mbstring extension.

== Frequently Asked Questions ==

= Will activation change my existing URLs? =

No. It affects slugs and file names created after you choose a standard.
Existing post slugs change only if you rewrite them from the "What would
change" screen.

= Why are existing pages and categories not converted? =

When a post slug changes, WordPress stores the old one and redirects visitors
from it. It does nothing of the kind for pages and terms, so a changed address
would break every link to it.

= Why are existing media files not renamed? =

A file's address appears in post content, in caches, in a CDN and on other
people's pages. Renaming it breaks all of those at once, and nothing can put
them back.

= Can I edit the transliteration table? =

No. A standard edited letter by letter stops matching the document it came
from, and that match is why you picked it. Use exceptions instead.

= My site is in two languages. Which one does it use? =

The language set on the post or term, if Polylang can tell it. Without a
language the text is left unchanged.

== Screenshots ==

1. A standard per language, each linked to the document it comes from. The
   preview beside every choice shows the address that choice would produce.
2. What your existing slugs would become, with the language each post is in.
   The whole list downloads as a CSV, and rewriting needs a tick and a click.
3. Exceptions are whole words and whole phrases, for brand names and for
   spellings someone's passport already carries.

== Changelog ==

= 0.1.0 =
* First release.
