30-секундный обзор: Я запустил скрипт статуса перевода, на экране вывелось 4546, всё в
root. На GitHub CI в Linux — зелёный. Позже выяснилось две вещи. Обратная косая черта в путях Windows, скрипт режет прямой — не вырезает. Второй байт Big5 у "gōng" — это сам ASCII\. Две вещи, механизмы разные, но часто встречаются вместе на одной и той же繁中 Windows.
Я поддерживаю скрипт статуса перевода Taiwan.md на Windows 11 с языковой настройкой zh-TW. В тот вечер, как обычно, запустил i18n-status.py, ждал, пока терминал выведет цифры. Консоль — cp950. В выводе не было красного текста.
Экран остановился на 4546. Всё в одной категории под названием root. Technology — 0.
В ту же неделю запушил на GitHub, CI в Linux — зелёный свет.
Переменная скрипта называется zh_articles, она сканирует пути под knowledge, кроме английского, about и директорий с подчёркиванием в начале; японский, корейский, арабский тоже попадают в счёт. В тот вечер он не смог даже вырезать имена категорий, четыре тысячи путей ушли в одну ячейку. Никаких исключений, никаких предупреждений. Статистика выглядела так, будто весь сайт сломан, файлов не хватало ни одного.1
На диске пути выглядят как knowledge\Technology\какая-то-статья.md, папки разделены обратной косой чертой. Скрипт использует split('/') чтобы достать имя категории. В Linux это работает, потому что пути изначально с прямой косой. В Windows он не находит обратную косую, вся путь возвращается как есть, статья попадает в дефолтный root.2
После того как отдал обработку директорий pathlib, под Technology оказалось 59 статей, совпадает с содержимым папки. Между ними разделяет лишь одно предположение: какой чертой ваша машина разделяет папки.
Один и тот же путь, два способа резать. split('/') не находит прямую косую, возвращает весь путь как есть; PureWindowsPath знает обратную косую, Technology возвращается. Taiwan.md Contributors, CC BY-SA 4.0.
📝 Заметка куратора: Синтаксис скрипта не ошибочен, CI действительно прогонял тесты. Разрыв там, где «машина, за которой реально сидит автор» и «машина, которой думает инструмент». Этому зазору не принадлежит ни один этап, поэтому никто не отвечает за его наблюдение.
«Gōng» внутри — та самая черта
Пути — первый слой. Второй слой старше гораздо, зарыт в самом иероглифе.
Big5 утвердили в 1984 году, один китайский иероглиф — два байта. Если второй байт попадает в 0x40–0x7E, он перекрывается с ASCII-символами: [, ], {, }, \, |. Профессор кафедры управления информацией Чаоянского технологического университета Хун Чаогуй (ушёл на пенсию в августе 2023 года) писал на учебной странице: «Поскольку 40–7E — это диапазон ASCII кодов общеупотребительных символов, это иногда создаёт программистам затруднения.»3
Код «gōng» — A5 5C. Тот самый 0x5C в ASCII — обратная косая черта \. Программа, сканирующая строку побайтово и воспринимающая \ как escape или разделитель, наткнувшись на вторую половину «gōng», решит, что встретила путь. «Gōng» в имени файла, «gōng» в пути — оба могут здесь разбиться.
Тайваньские и гонконгские разработчики называют это «Сюй Гуньгай» (許功蓋): «Сюй» — B3 5C, «Gōng» — A5 5C, «Гай» — BB 5C, три частоупотребительных иероглифа подряд похожи на имя человека.4 Хун Чаогуй дополнительно перечислил «Цзя Е Чэнь Чжэнь Гун» (加也程陣功), вторые байты которых наезжают на [, ], {, }, \, и написал сканер b5tm.3 Багу дают человеческое имя обычно потому, что она встречается достаточно часто, и поколению нужно уметь указывать на неё и говорить.
В 2015 году автор блога «Тёмная нить» перешёл на Visual Studio 2015. Старые .cs всё ещё сохранялись в BIG5. После перехода компилятора на Roslyn, Сюй Гуньгай внутри файлов превращались в ошибки компиляции.
Через два дня коллега сказал, они тоже перешли и застряли надолго, в итоге полезли в поиск и попали обратно к той его статье. У одного читателя были тысячи файлов, конвертировал один — ещё куча, «пришлось сказать VS2015 Goodbye». Позже он написал маленький батник для пакетной конвертации в UTF-8, потому что ручное «Сохранить как» не успевал.5
Это не то же самое, что split('/') выше. Одно — современные инструменты предполагают, как выглядит путь. Другое — сорок лет назад выбрали двухбайтовое представление, и внутри тела иероглифа поселился символ. Механизмы разные, но счета часто приходят вместе на одной и той же cp950 машине. Как с той стороны вводят иероглифы в компьютер — см. восточноазиатские методы ввода. Здесь речь о том, когда иероглиф уже на диске, узнаёт ли его цепочка инструментов.
Умолчания не открывали для этой машины ветку
Git по умолчанию включает core.quotePath. Имена файлов с байтами больше 0x80, git status печатает как \344\270\255 — такие восьмеричные последовательности. Китайские имена файлов на месте, просто вы каждый день не понимаете, что говорит ваш репозиторий.6 Он экранирует старшие байты UTF-8. Big5 0x5C — другая линия. Выглядят обе как обратная косая черта, природы разные.
Один и тот же файл, под дефолтом — строка \345\212\237. Здесь обратная косая черта — экранирование, добавленное Git'ом, отношения к тому 0x5C внутри «gōng» не имеет. Taiwan.md Contributors, CC BY-SA 4.0.
Python 3 в Windows, если open() без encoding='utf-8', может унаследовать системную локаль. Тот же UTF-8 файл, Linux прочитает, эта машина через cp950 попытается раскодировать — пунктуация или жуинь сломаются.7 Я сам платил один раз: использовал PowerShell 5.1 Get-Content | Set-Content чтобы переделать UTF-8 файл, длинное тире в diff превратилось в ??. Тот тоже налог на умолчания, не вторая тема.
Когда статус-сообщения несут emoji, эта cp950 консоль падает напрямую. В наборе символов их нет, Python не может напечатать, исключение летит наверх. Linux CI это не ловит, потому что не на этой машине гоняет.
Git, Python, примеры путей в CI с $HOME/project/src — не открывали для zh-TW Windows отдельную ветку.
Хун Чаогуй в 2015 году дал интервью iThome, говорил, в каком формате правительству открывать файлы и как долго они живут. Репортаж передаёт его смысл: если правительство только продуктами Microsoft открывает файлы данных, это равносильно вере, что срок жизни Microsoft будет длиннее Китайской Республики.8 Та фраза про форматы файлов и сроки хранения. К какой цепочке дефолтных инструментов привязаны данные, время растянешь — становится вопросом, кто ещё сможет прочитать. Открытая коллаборация привязана к дефолтному окружению определённого типа машины. Напряжение между гражданскими технологиями и правительственными форматами файлов — см. сообщество открытого кода и g0v. Культура, которой тайваньские разработчики долго поглощали этот разрыв — см. тайваньский дух открытого кода.
Разделитель путей, кодировка терминала, $HOME в примерах CI — не было ветки, открытой для этой машины. В тот день, когда 4546 путей ушли не в ту категорию, ни одна строка кода не сообщила об ошибке. Статистика выглядела нормально, пока ты не сел за эту машину.
Дополнительное чтение
- тайваньский дух открытого кода: культура и контекст участия тайваньских разработчиков в открытом коде.
- восточноазиатские методы ввода: как иероглифы вбиваются в компьютер, от таблиц кодов до клавиатур.
- сообщество открытого кода и g0v: сотрудничество между открытыми данными и правительственными форматами.
Источники изображений
- Код Big5 «gōng» и обратная косая черта (hero): инфографика Taiwan.md Contributors, CC BY-SA 4.0, хранится в
public/article-images/technology/big5-gong-5c-backslash.webp. Нижняя строка — реальный вывод Python 3'許功蓋'.encode('big5'), кодовые позиции совпадают со статьёй Википедии о Big5.4 - split('/') против PureWindowsPath: Taiwan.md Contributors, CC BY-SA 4.0, хранится в
public/article-images/technology/windows-path-split-vs-pathlib.svg. Содержимое — реальные результаты выполнения Python 3;PureWindowsPathна любой ОС режет пути по правилам Windows, поэтому не нужна Windows-машина для воспроизведения. - Восьмеричный вывод Git core.quotePath: Taiwan.md Contributors, CC BY-SA 4.0, хранится в
public/article-images/technology/git-quotepath-octal-cjk.svg. Содержимое — реальный выводgit status --shortпосле добавления имени файла этой статьи во временный репозиторий; это поведение не зависит от ОС.
Ссылки
- taiwan-md PR #1260 — влит 2026-07-26. До фикса в Windows categories только root: 4546, после — Technology zh: 59. Одновременно убрали emoji, ронявшие cp950 консоль.↩
- Microsoft Learn: формат путей файлов в Windows — документация .NET объясняет, что классические DOS-пути используют обратную косую черту как разделитель директорий, прямая косая черта конвертируется в обратную.↩
- Хун Чаогуй: проблемы кода Big5, с которыми можно столкнуться при программировании — учебная страница перечисляет частоупотребительные иероглифы, вторые байты которых попадают в опасный ASCII-диапазон (Цзя Е Чэнь Чжэнь Гун), и представляет сканер b5tm. Внизу страницы должность не указана. iThome 2015 года называет его профессором. На его личной странице указано 1997–2023 гг. работа в Чаоянском управлении информацией, уход на пенсию в августе 2023 года.↩2
- Википедия: Big5 — указано «gōng» 0xA55C, «Сюй» 0xB35C, «Гай» 0xBB5C, и поясняется, что эту проблему шутят называют Сюй Гуньгай.↩2
- Тёмная нить: Потенциальный щит — решение проблемы совместимости BIG5 в VS2015 — запись 2015 года о том, как Visual Studio 2015 при компиляции исходников в BIG5 ломается на Сюй Гуньгай. В тексте есть «пришлось сказать VS2015 Goodbye».↩
- git-config: core.quotePath — официальная документация объясняет, что по умолчанию пути с байтами больше 0x80 отображаются как восьмеричные escape-последовательности.↩
- Python 3: open() — документация функции указывает, что при неуказанном encoding может использоваться системная локаль как кодировка по умолчанию.↩
- iThome: интервью Хун Чаогуй — интервью 2015 года, в тексте назван профессором кафедры управления информацией Чаоянского технологического университета. Оригинальная страница часто отдаёт 403, фраза про срок жизни Microsoft приводится только по пересказу в результатах поиска, не как дословная цитата.↩