Lokalizační chyták: MissingManifestResourceException

Lokalizace je zábavná, když funguje, ale když ne, dokáže způsobit pořádný bolehlav. Zažil jsem jej sám ve formě záhadné výjimky MissingManifestResourceException  a chci se s vámi podělit o to, kdy k ní dochází a také jako připomínku, abych si na řešení příště vzpomněl rychleji 🙂 .

Sdílení zdrojů – RESX

UWP aplikace přidal nový formát pro správu zdrojů (resources) – RESW. Prakticky jde o starý dobrý formát RESX, jen s jinou příponou. Pravdou však je, že vývojáři mobilních aplikací pro více platforem preferují sdílení řetězcových zdrojů a za tímto účelem využijí Portable Class Library.

Takovéto sdílení zdrojů je poměrně snadné nastavit. Nejprve vytvoříte novou knihovnu PCL, přidáte soubor RESX, nastavíte generování jeho kódu na public a poté přidáte více lokalizovaných resource souborů se stejným názvem ale názevm cílové kultury na konci – např. LocalizedStrings.resx (neutrální), LocalizedStrings.de.resx (německý), LocalizedStrings.cs.resx (český).

Za běhu je systémem zkontrolována  CultureInfo.CurrentUICulture  a podle ní se načtou lokalizované verze požadovaných zdrojů.

Toto funguje téměř stoprocentně. Dokud nenarazíte na   MissingManifestResourceException .

Dvě formy MissingManifestResourceException

V mém případě výjimka začala vyskakovat při jednoduchém přístupu k lokalizovanému řetězcovému zdroji:

First form of the exception
První forma výjimky

Všiml jsem si v popisu chyby reference na RESW soubory a tak jsem zkusil přidat do projektu UWP aplikace RESW zdrojové soubory pro všechny podporované jazyky Upozorňuji, že toto je nutné v každém případě! Pokud RESW soubory v projektu nezahrnete, při vytváření balíku aplikace nebudou lokalizované zdroje rozpoznány a aplikace pak nebude v těch jazycích, které jste přeložili k dispozici. Důvodem je element  <Resource Language="x-generate"/> , kerý najdete v souboru Package.appxmanifest.

Po rebuildu a znovuspuštění aplikace výjimka zůstala. Po troše dalšího boje s třídou ResourceManager se popis výjimky změnil na ještě “užitečnější”:

Byl jsem úplně ztracen, dokud jsem nezkusil něco na první pohled neintuitivního – změnil jsem jméno PCL assembly.

Nezakončujte jméno vaší PCL suffixem “.Resources”!

Nadpis říká vše. Pokud zakončíte název vaší PCL suffixem .Resources, vaše aplikace spadne s výjimkou MissingManifestResourceException . Vše ostatní bude fungovat skvěle a kompilace se bude také tvářit nevinně. Také, aby bylo vše trochu více “Sherlockovské”, k výjimce dojde pouze při pokusu o přístup na přeložené zdroje, tedy ne pokud budete mít nastavenou jazyk odpovídající neutrální kultuře aplikace.

Když jsem přejmenoval assembly tak aby její název končil .Localization (nebo ostatně čímkoliv jiným), aplikace již nepadá a zdroje se načítají správně.

Zdrojový kód

Ukázkový projekt s PCL s .Resources .Localization v názvu je dostupný na mém GitHubu. Můžete si ověřit, že při pokusu o načtení zdroje z prvního PCL dojde k výjimce.

Shrnutí

Tento RESX + PCL bug není snadné vystopovat, protože způsobuje chybu jen za běhu a to ještě pouze při správném nastavení kultury. Bohužel je poměrně snadné jej způsobit, protože nastavit PCL s resources pojmenování se suffixem “.Resources je celkem logické 🙂 .

3 odpovědi na “Lokalizační chyták: MissingManifestResourceException”

  1. Uvízl jsem ve stejné pasti “Lokalizační chyták: MissingManifestResourceException”

    snažím se porozumět ale nerozumím dvěma věcem na která bych se rád zeptal.

    1. Co to znamená “pro všechny podporované jazyky” ve větě “Všiml jsem si v popisu chyby reference na RESW soubory a tak jsem zkusil přidat do projektu UWP aplikace RESW zdrojové soubory pro všechny podporované jazyky ” Jsou to všechny podporované jazyky v operačním systému?

    2. Jak mohu změnit jméno PCL? protože jsme se v tomhle nikdy nehrabal tak jsme z toho poněkud zmatený.

    Díky za pomoc

    Petr

      1. Není třeba všechny jazyky systému, ale všechny jazyky, které chcete, aby vaše aplikace podporovala 🙂
      2. Jméno PCL jde na několik kroků. Hlavním je změna assembly name – pravým tlačítkem na PCL projekt v Solution Exploreru -> Properties -> na záložce Library najdete políčka Assembly Name a Default Namespace, která změňte obě na cílový název. Potom je také možná užitečné pro kompletnost změnit název projektu v solution exploreru (kliknutím na jeho název a stisknutím F2) a změnou namespace jednotlivých tříd v něm (to už je potřeba udělat manuálně v jednotlivých cs souborech)

      Snad to pomůže 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

*