Wallet pass default localization rules

There must be some rules that determine which set of localized strings of an Apple Wallet pass (.pkpass) is used when the choice is not obvious.

For instance, I made a pass with localization folders

  • ko.lproj (Korean)
  • pl.lproj (Polish)
  • zh-Hans.lproj (Chinese).

If any of these languages is in my iPhone's preferred languages (Settings... General... Language & Region), then it's easy: the first one on that list is used. But what if the list does not have any of them?

When I try, it seems the Chinese localization is chosen by the Wallet app. Without the Chinese localization folder, it is Korean. If I also add

  • ar.lproj (Arabic)

then Arabic is chosen.

I can't discern any system here. How does Wallet choose the default localization?

Answered by BvdG in 791083022

After some experimenting, I think I have found the answer. When phone settings don't match any of the localization folders present in the .pkpass archive, Wallet uses the localization folder that comes first in the file order of the filesystem.

Wallet seems to use the first localization folder delivered by libc's readdir function when run on the contents of the .pkpass. That function's manpage says:

Note that the order of the directory entries vended by readdir() is not specified. Some filesystems may return entries in lexicographic sort order and others may not.

So in the case of iPhone and its Wallet app, the order is determined by the APFS filesystem. It's based on filenames, but not alphabetical. An old FAQ explains,

Calling readdir(2) on a directory in APFS returns filenames in hash order,

where the hash consists of 22 bits of a CRC-32C hash of the null-terminated normalized filename in UTF-32, according to the APFS reference.

In practical terms, the user gets a random localization when none of the locales in the pass is set as one of the preferred languages.

The priority order of localizations (for a list of 144 localization codes) is:

de, ur, he, en_AU, zh-Hant-TW, ar, el, zh-Hans, ja, fa, zh-TW, mr, el-GR, ms-MY, mk, sq, uk-UA, eu, en, it-IT, co, zh-Hant-HK, hi_IN, uk, es_419, da_DK, kab, gu, es_MX, ku, nb-NO, zh_CN, kn, nb, pa, ca-ES, en-GB, am, es, sw, is, sl, ru-RU, nl_NL, pt_BR, da, gl, es-419, et, it, sv_SE, bg, sk, kk, pt_PT, fr-CA, sat, tr-TR, es-ES, sr, ms, ar-SA, si, be, ta, ne, fr-FR, ml, ja-JP, sv, ko-KR, id-ID, te, cs, km, ko, vi-VN, fil, th_TH, an, zh-Hant, sc, my, uk_UA, no, fa-IR, ro-RO, hu, hr-HR, da-DK, hi-IN, zh_HK, ka, bn-IN, ga, tr, ast, pl, zh_TW, hu-HU, gu-IN, en_GB, br, pt-BR, brx, nl-NL, vi, lv, es-MX, lt, ru, cy, cs-CZ, nb_NO, zh-CN, af, sk-SK, de-DE, sl-SI, fr_CA, es_ES, fr, fi, id, nl, th, pl-PL, nn, pt, de-CH, as-IN, sv-SE, bn, pt-PT, oc, gl-ES, he-IL, ro, th-TH, wa, hr, hi, ca, gd

Good luck finding a pattern in that.

Accepted Answer

After some experimenting, I think I have found the answer. When phone settings don't match any of the localization folders present in the .pkpass archive, Wallet uses the localization folder that comes first in the file order of the filesystem.

Wallet seems to use the first localization folder delivered by libc's readdir function when run on the contents of the .pkpass. That function's manpage says:

Note that the order of the directory entries vended by readdir() is not specified. Some filesystems may return entries in lexicographic sort order and others may not.

So in the case of iPhone and its Wallet app, the order is determined by the APFS filesystem. It's based on filenames, but not alphabetical. An old FAQ explains,

Calling readdir(2) on a directory in APFS returns filenames in hash order,

where the hash consists of 22 bits of a CRC-32C hash of the null-terminated normalized filename in UTF-32, according to the APFS reference.

In practical terms, the user gets a random localization when none of the locales in the pass is set as one of the preferred languages.

The priority order of localizations (for a list of 144 localization codes) is:

de, ur, he, en_AU, zh-Hant-TW, ar, el, zh-Hans, ja, fa, zh-TW, mr, el-GR, ms-MY, mk, sq, uk-UA, eu, en, it-IT, co, zh-Hant-HK, hi_IN, uk, es_419, da_DK, kab, gu, es_MX, ku, nb-NO, zh_CN, kn, nb, pa, ca-ES, en-GB, am, es, sw, is, sl, ru-RU, nl_NL, pt_BR, da, gl, es-419, et, it, sv_SE, bg, sk, kk, pt_PT, fr-CA, sat, tr-TR, es-ES, sr, ms, ar-SA, si, be, ta, ne, fr-FR, ml, ja-JP, sv, ko-KR, id-ID, te, cs, km, ko, vi-VN, fil, th_TH, an, zh-Hant, sc, my, uk_UA, no, fa-IR, ro-RO, hu, hr-HR, da-DK, hi-IN, zh_HK, ka, bn-IN, ga, tr, ast, pl, zh_TW, hu-HU, gu-IN, en_GB, br, pt-BR, brx, nl-NL, vi, lv, es-MX, lt, ru, cy, cs-CZ, nb_NO, zh-CN, af, sk-SK, de-DE, sl-SI, fr_CA, es_ES, fr, fi, id, nl, th, pl-PL, nn, pt, de-CH, as-IN, sv-SE, bn, pt-PT, oc, gl-ES, he-IL, ro, th-TH, wa, hr, hi, ca, gd

Good luck finding a pattern in that.

Wallet pass default localization rules
 
 
Q