static/_headers was removed by 'make clean' (rm -rf static/_*) and got
copied into every non-default locale's build output, where it had no
effect since none of its rules matched locale-prefixed paths. Move the
file to cloudflare/_headers, which is outside static/ and is copied into
build/_headers by the Cloudflare Pages workflow step, after the S3 sync
step has already run so the file is never uploaded to S3/CloudFront.
Add /:locale/assets/*, /:locale/img/* and /:locale/images/* rules so the
caching also applies to the zh-cn and zh-tw locale copies Docusaurus
produces (docusaurus.config.js locales: en-us, zh-cn, zh-tw), which were
still falling back to Cloudflare's default max-age=0 caching. A named
placeholder is used instead of a second '*' splat or an explicit list of
locales, since Cloudflare Pages only allows one splat per path and this
way the rule keeps matching if a locale is ever added or removed.
Revert the earlier aws s3 sync --exclude "_headers" change: with
_headers no longer living under static/, it is never present in build/
at S3 sync time, so the exclude has nothing to do.
Cloudflare Pages currently serves all responses with the default
'Cache-Control: public, max-age=0, must-revalidate', including
content-hashed files under /assets/* produced by the Docusaurus
build. Add a static/_headers file so Cloudflare Pages applies
long-lived immutable caching to /assets/* (safe because the filename
changes whenever the content changes) and a conservative one-day
max-age to /img/* and /images/*, which keep stable filenames and can
be replaced in place.
Also exclude _headers from the aws s3 sync step in the publish
workflow, since it is only meaningful for the Cloudflare deployment
and would otherwise be uploaded to S3/CloudFront and become publicly
accessible at /_headers there.