[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M73H1GSBC974EBYEJB0BJCSJ":3,"skill-same:01M73H1GSBC974EBYEJB0BJCSJ":60},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":18,"linkOnly":19,"markdownContent":20,"markdownBody":21,"frontMatter":22,"refName":38,"commitSha":39,"skillDirectory":40,"forksCount":41,"repositoryHtmlUrl":42,"repositoryHomepageUrl":6,"ownerHtmlUrl":43,"ownerBlogUrl":6,"ownerDescription":44,"updatedAt":45,"install":46,"resources":59},"01M73H1GSBC974EBYEJB0BJCSJ","i18n-locale-config",null,"Locale identification and configuration: BCP 47 locale ID structure, the language-vs-country doctrine, per-language collation order, timezone handling, and the region\u002Flanguage matrix. Use when: choosing a locale code, configuring locales\u002F\u003Clang>.json, fixing sort order for a language, or deciding which timezone a deliverable should display.","5throck\u002Fai-workspace-standards","5throck","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F10958964?v=4","01M73BFEH0V0VS483TW4JD49JW","01M73BFEJ5VQZJHJSFTVPAZGDM",25,"AGPL-3.0","https:\u002F\u002Fgithub.com\u002F5throck\u002Fai-workspace-standards\u002Fblob\u002Fmain\u002Ftemplates\u002Fcommon\u002F.gemini\u002Fskills\u002Fi18n-locale-config\u002FSKILL.md",[],[],"2026-11-11 15:11:14",false,"---\nname: i18n-locale-config\ndescription: >\n  Locale identification and configuration: BCP 47 locale ID structure,\n  the language-vs-country doctrine, per-language collation order,\n  timezone handling, and the region\u002Flanguage matrix. Use when: choosing\n  a locale code, configuring locales\u002F\u003Clang>.json, fixing sort order for\n  a language, or deciding which timezone a deliverable should display.\nversion: 1.0.1\nowner: i18n-specialist\nstatus: active\nlast_reviewed: 2026-08-24\nscope: common\nmetadata:\n  type: process\n  triggers:\n    - locale config\n    - locale code\n    - BCP 47\n    - collation\n    - collation order\n    - timezone\n---\n\n## Purpose\n\nDefines how the workspace identifies and configures locales. A locale ID is not decoration — it selects collation order, date\u002Fnumber rendering (see the `i18n-formatting` skill), casing rules, and default timezone display. This skill covers ID structure, the country ≠ language doctrine, collation, timezones, and the supported-locale matrix.\n\n## BCP 47 Locale ID Structure\n\nLocale IDs follow **BCP 47 \u002F IETF language tags**: `language[-Script][-REGION][-variant]`.\n\n| Subtag | Case | Examples | Notes |\n|--------|------|----------|-------|\n| `language` | lowercase | `en`, `ko`, `zh`, `pt` | ISO 639-1 (two-letter) primary language |\n| `Script` | Titlecase | `Hans`, `Hant`, `Latn` | ISO 15924; usually inferable, required when a language uses multiple scripts |\n| `REGION` | UPPERCASE | `KR`, `CN`, `TW`, `CH`, `BR` | ISO 3166-1 alpha-2; selects regional conventions, not the country itself |\n| variant | lowercase | `valencia` | Rare; only when a subtag genuinely changes behavior |\n\n**Canonical examples in this workspace**:\n\n- `ko` — Korean (region `KR` implied by convention; add `-KR` only when disambiguating)\n- `zh-CN` — Chinese, Simplified script, mainland conventions (Script `Hans` implied)\n- `zh-TW` — Chinese, Traditional script, Taiwan conventions (Script `Hant` implied)\n- `de-CH` — German with Swiss conventions (e.g. `ss` instead of `ß`)\n- `pt-BR` vs `pt-PT` — Brazilian and European Portuguese differ in spelling and formal address\n\n**Rules**:\n\n1. Case is normative: `zh-cn` is malformed; write `zh-CN`.\n2. Do not invent region subtags to encode a target country — the target country lives in the variant's `country_config`, never in i18n settings (see below).\n3. Locale files follow constitution §4.2: `locales\u002F\u003Clang-code>.json`, flat key-value, with `en.json` as the source of truth for every key.\n\n## Language ≠ Country\n\nConstitution §4.3 doctrine — the two axes are independent:\n\n- **One country, many languages**: CH → `de`\u002F`fr`\u002F`it`; a Swiss deliverable needs a language decision before a locale decision.\n- **One language, many countries**: `en` spans dozens of countries; `en` alone does not encode a market.\n- **`zh-CN` \u002F `zh-TW` are language+region hybrids** — they are locale IDs, never country codes. Mapping \"Taiwan market\" to `zh-TW` for *content language* is correct; storing `zh-TW` in a country field is a data-model error.\n- A country profile's *Language & Communication Defaults* section **references** `i18n.locale_codes`; it never redefines the project's documentation language.\n\nConsequence for asset registration: language-scoped assets (this suite, the `translate` skill) are never registered in `country_scoped_assets` — that registry is for skills whose **data access** is jurisdiction-specific.\n\n## Collation\n\nSort order is locale-specific. Default Unicode code-point order (what `Array.prototype.sort` does without a comparator) is **wrong for almost every non-English locale**.\n\n**Always use `Intl.Collator` (or the platform equivalent) with an explicit locale:**\n\n```js\n\u002F\u002F WRONG — code-point order ignores locale collation rules\n[\"zeta\", \"Arche\", \"apple\"].sort();\n\n\u002F\u002F RIGHT — locale collation (German: umlauts follow locale-specific ordering)\n[\"zeta\", \"Arche\", \"apple\"].sort(new Intl.Collator(\"de\").compare);\n```\n\n**Korean collation specifics** (romanized terms — Korean text itself belongs in Korean deliverables, not in English documentation):\n\n- Korean sorts in **ganada order** — the syllabary's canonical sequence, whose first three syllables romanize as ga-na-da. This is the dictionary order a Korean reader expects.\n- Ganada order is **not** Unicode code-point order: plain `Array.prototype.sort()` on Korean text yields code-block order, which misplaces extended and rarely-used syllables. `Intl.Collator(\"ko\")` applies ganada order correctly — never sort Korean strings without it.\n- Mixing Hangul and Latin in one list: `ko` collation conventionally places ASCII after Hangul; verify with the actual collator rather than assuming.\n\n**Collation options that matter**:\n\n| Option | Effect | Use when |\n|--------|--------|----------|\n| `numeric: true` | \"file-2\" sorts before \"file-10\" | Sorting identifiers, filenames, numbered sections |\n| `sensitivity: \"base\"` | Case- and accent-insensitive | User-facing search\u002Fdedup |\n| `sensitivity: \"variant\"` | Full distinction (default for many locales) | When diacritics change meaning (`de` umlauts) |\n| `ignorePunctuation: true` | Skips punctuation weights | Loose list sorting |\n\n**Locale-divergent examples**: Swedish `ö` sorts after `z` (not next to `o` as in German); German `ä` may sort as `ae` in phone-book order (`de-DE-u-co-phonebk`). When sorting user-visible lists, pin the locale explicitly and test with accented input.\n\n## Timezone Handling\n\n**Rules**:\n\n1. **Store and interchange in UTC** (or an explicit offset); convert only at display time.\n2. **Name timezones with IANA identifiers** — `Asia\u002FSeoul`, `Europe\u002FZurich`, `America\u002FNew_York`. Never store fixed abbreviations (`KST`, `CET`) as primary data: they are ambiguous and ignore daylight-saving transitions.\n3. **Display per locale**: the same instant renders with different conventions per locale.\n\n```js\n\u002F\u002F Same instant, two locales — note date can differ across zones\nnew Intl.DateTimeFormat(\"en-US\", {\n  timeZone: \"Asia\u002FSeoul\",\n  dateStyle: \"medium\",\n  timeStyle: \"short\",\n}).format(new Date(\"2026-08-24T15:00:00Z\"));\n\u002F\u002F \"Aug 25, 2026, 12:00:00 AM\" (KST is UTC+9, no DST)\n\nnew Intl.DateTimeFormat(\"ko\", {\n  timeZone: \"Asia\u002FSeoul\",\n  dateStyle: \"medium\",\n  timeStyle: \"short\",\n}).format(new Date(\"2026-08-24T15:00:00Z\"));\n\u002F\u002F Korean-locale rendering of the same midnight instant\n```\n\n**Convention notes**:\n\n- `Asia\u002FSeoul` is UTC+9 with **no daylight-saving time** — safe for fixed-offset reasoning, but still use the IANA name.\n- US zones (`America\u002F*`) shift twice a year; never cache a fixed offset for them.\n- A locale does not determine a timezone: `en` renders in whatever zone the user is in. Locale selects *format*; timezone is a separate, explicit parameter.\n\n## Region\u002FLanguage Matrix\n\nThe baseline set is the **16 supported locales** of constitution §4.1: `en` (default), `ko`, `ja`, `zh-CN`, `zh-TW`, `de`, `es`, `fr`, `pt`, `vi`, `ms`, `id`, `th`, `ru`, `it`, `ar`.\n\nWhen configuring a project or adding a locale:\n\n1. Start from the variant's actual audience — a region\u002Flanguage matrix row exists only when the market needs it (e.g. `CH → de, fr, it`).\n2. Every key present in any locale file must exist in `en.json` (§4.2); missing keys fail closed to `en`.\n3. Adding a locale is a language decision. Adding a country profile is a jurisdiction decision (constitution §7.3.5, ADR-0057). They proceed through different registries and must not be conflated.\n4. `ar` activation implies RTL layout obligations — see the `i18n-layout` skill before shipping an `ar` locale.\n\n## Boundary\n\n- Rendering formats (dates, numbers, currency) for a chosen locale: `i18n-formatting`.\n- Encoding, RTL\u002Fbidi mechanics, fonts: `i18n-layout`.\n- Translating a specific file (hash sync, diff preview): the `translate` skill.\n","## Purpose\n\nDefines how the workspace identifies and configures locales. A locale ID is not decoration — it selects collation order, date\u002Fnumber rendering (see the `i18n-formatting` skill), casing rules, and default timezone display. This skill covers ID structure, the country ≠ language doctrine, collation, timezones, and the supported-locale matrix.\n\n## BCP 47 Locale ID Structure\n\nLocale IDs follow **BCP 47 \u002F IETF language tags**: `language[-Script][-REGION][-variant]`.\n\n| Subtag | Case | Examples | Notes |\n|--------|------|----------|-------|\n| `language` | lowercase | `en`, `ko`, `zh`, `pt` | ISO 639-1 (two-letter) primary language |\n| `Script` | Titlecase | `Hans`, `Hant`, `Latn` | ISO 15924; usually inferable, required when a language uses multiple scripts |\n| `REGION` | UPPERCASE | `KR`, `CN`, `TW`, `CH`, `BR` | ISO 3166-1 alpha-2; selects regional conventions, not the country itself |\n| variant | lowercase | `valencia` | Rare; only when a subtag genuinely changes behavior |\n\n**Canonical examples in this workspace**:\n\n- `ko` — Korean (region `KR` implied by convention; add `-KR` only when disambiguating)\n- `zh-CN` — Chinese, Simplified script, mainland conventions (Script `Hans` implied)\n- `zh-TW` — Chinese, Traditional script, Taiwan conventions (Script `Hant` implied)\n- `de-CH` — German with Swiss conventions (e.g. `ss` instead of `ß`)\n- `pt-BR` vs `pt-PT` — Brazilian and European Portuguese differ in spelling and formal address\n\n**Rules**:\n\n1. Case is normative: `zh-cn` is malformed; write `zh-CN`.\n2. Do not invent region subtags to encode a target country — the target country lives in the variant's `country_config`, never in i18n settings (see below).\n3. Locale files follow constitution §4.2: `locales\u002F\u003Clang-code>.json`, flat key-value, with `en.json` as the source of truth for every key.\n\n## Language ≠ Country\n\nConstitution §4.3 doctrine — the two axes are independent:\n\n- **One country, many languages**: CH → `de`\u002F`fr`\u002F`it`; a Swiss deliverable needs a language decision before a locale decision.\n- **One language, many countries**: `en` spans dozens of countries; `en` alone does not encode a market.\n- **`zh-CN` \u002F `zh-TW` are language+region hybrids** — they are locale IDs, never country codes. Mapping \"Taiwan market\" to `zh-TW` for *content language* is correct; storing `zh-TW` in a country field is a data-model error.\n- A country profile's *Language & Communication Defaults* section **references** `i18n.locale_codes`; it never redefines the project's documentation language.\n\nConsequence for asset registration: language-scoped assets (this suite, the `translate` skill) are never registered in `country_scoped_assets` — that registry is for skills whose **data access** is jurisdiction-specific.\n\n## Collation\n\nSort order is locale-specific. Default Unicode code-point order (what `Array.prototype.sort` does without a comparator) is **wrong for almost every non-English locale**.\n\n**Always use `Intl.Collator` (or the platform equivalent) with an explicit locale:**\n\n```js\n\u002F\u002F WRONG — code-point order ignores locale collation rules\n[\"zeta\", \"Arche\", \"apple\"].sort();\n\n\u002F\u002F RIGHT — locale collation (German: umlauts follow locale-specific ordering)\n[\"zeta\", \"Arche\", \"apple\"].sort(new Intl.Collator(\"de\").compare);\n```\n\n**Korean collation specifics** (romanized terms — Korean text itself belongs in Korean deliverables, not in English documentation):\n\n- Korean sorts in **ganada order** — the syllabary's canonical sequence, whose first three syllables romanize as ga-na-da. This is the dictionary order a Korean reader expects.\n- Ganada order is **not** Unicode code-point order: plain `Array.prototype.sort()` on Korean text yields code-block order, which misplaces extended and rarely-used syllables. `Intl.Collator(\"ko\")` applies ganada order correctly — never sort Korean strings without it.\n- Mixing Hangul and Latin in one list: `ko` collation conventionally places ASCII after Hangul; verify with the actual collator rather than assuming.\n\n**Collation options that matter**:\n\n| Option | Effect | Use when |\n|--------|--------|----------|\n| `numeric: true` | \"file-2\" sorts before \"file-10\" | Sorting identifiers, filenames, numbered sections |\n| `sensitivity: \"base\"` | Case- and accent-insensitive | User-facing search\u002Fdedup |\n| `sensitivity: \"variant\"` | Full distinction (default for many locales) | When diacritics change meaning (`de` umlauts) |\n| `ignorePunctuation: true` | Skips punctuation weights | Loose list sorting |\n\n**Locale-divergent examples**: Swedish `ö` sorts after `z` (not next to `o` as in German); German `ä` may sort as `ae` in phone-book order (`de-DE-u-co-phonebk`). When sorting user-visible lists, pin the locale explicitly and test with accented input.\n\n## Timezone Handling\n\n**Rules**:\n\n1. **Store and interchange in UTC** (or an explicit offset); convert only at display time.\n2. **Name timezones with IANA identifiers** — `Asia\u002FSeoul`, `Europe\u002FZurich`, `America\u002FNew_York`. Never store fixed abbreviations (`KST`, `CET`) as primary data: they are ambiguous and ignore daylight-saving transitions.\n3. **Display per locale**: the same instant renders with different conventions per locale.\n\n```js\n\u002F\u002F Same instant, two locales — note date can differ across zones\nnew Intl.DateTimeFormat(\"en-US\", {\n  timeZone: \"Asia\u002FSeoul\",\n  dateStyle: \"medium\",\n  timeStyle: \"short\",\n}).format(new Date(\"2026-08-24T15:00:00Z\"));\n\u002F\u002F \"Aug 25, 2026, 12:00:00 AM\" (KST is UTC+9, no DST)\n\nnew Intl.DateTimeFormat(\"ko\", {\n  timeZone: \"Asia\u002FSeoul\",\n  dateStyle: \"medium\",\n  timeStyle: \"short\",\n}).format(new Date(\"2026-08-24T15:00:00Z\"));\n\u002F\u002F Korean-locale rendering of the same midnight instant\n```\n\n**Convention notes**:\n\n- `Asia\u002FSeoul` is UTC+9 with **no daylight-saving time** — safe for fixed-offset reasoning, but still use the IANA name.\n- US zones (`America\u002F*`) shift twice a year; never cache a fixed offset for them.\n- A locale does not determine a timezone: `en` renders in whatever zone the user is in. Locale selects *format*; timezone is a separate, explicit parameter.\n\n## Region\u002FLanguage Matrix\n\nThe baseline set is the **16 supported locales** of constitution §4.1: `en` (default), `ko`, `ja`, `zh-CN`, `zh-TW`, `de`, `es`, `fr`, `pt`, `vi`, `ms`, `id`, `th`, `ru`, `it`, `ar`.\n\nWhen configuring a project or adding a locale:\n\n1. Start from the variant's actual audience — a region\u002Flanguage matrix row exists only when the market needs it (e.g. `CH → de, fr, it`).\n2. Every key present in any locale file must exist in `en.json` (§4.2); missing keys fail closed to `en`.\n3. Adding a locale is a language decision. Adding a country profile is a jurisdiction decision (constitution §7.3.5, ADR-0057). They proceed through different registries and must not be conflated.\n4. `ar` activation implies RTL layout obligations — see the `i18n-layout` skill before shipping an `ar` locale.\n\n## Boundary\n\n- Rendering formats (dates, numbers, currency) for a chosen locale: `i18n-formatting`.\n- Encoding, RTL\u002Fbidi mechanics, fonts: `i18n-layout`.\n- Translating a specific file (hash sync, diff preview): the `translate` skill.\n",{"name":5,"owner":23,"scope":24,"status":25,"version":26,"metadata":27,"description":36,"last_reviewed":37},"i18n-specialist","common","active","1.0.1",{"type":28,"triggers":29},"process",[30,31,32,33,34,35],"locale config","locale code","BCP 47","collation","collation order","timezone","Locale identification and configuration: BCP 47 locale ID structure, the language-vs-country doctrine, per-language collation order, timezone handling, and the region\u002Flanguage matrix. Use when: choosing a locale code, configuring locales\u002F\u003Clang>.json, fixing sort order for a language, or deciding which timezone a deliverable should display.\n",1787529600000,"main","b57e612781a79b0e3e60878294ce59c86cc68e5d","templates\u002Fcommon\u002F.gemini\u002Fskills\u002Fi18n-locale-config",9,"https:\u002F\u002Fgithub.com\u002F5throck\u002Fai-workspace-standards","https:\u002F\u002Fgithub.com\u002F5throck","Experienced in digital transformation, enterprise IT, startup acceleration, and business strategy. Focused on building practical systems that connect technolo","2026-11-14 21:22:34",{"source":8,"skillName":5,"commands":47,"prompt":57,"zipAvailable":58},[48,51,54],{"tool":49,"command":50},"npx","npx skills add 5throck\u002Fai-workspace-standards --skill i18n-locale-config",{"tool":52,"command":53},"bunx","bunx skills add 5throck\u002Fai-workspace-standards --skill i18n-locale-config",{"tool":55,"command":56},"pnpm","pnpm dlx skills add 5throck\u002Fai-workspace-standards --skill i18n-locale-config","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002F5throck\u002Fai-workspace-standards\u002Fblob\u002Fmain\u002Ftemplates\u002Fcommon\u002F.gemini\u002Fskills\u002Fi18n-locale-config\u002FSKILL.md",true,[],[61,69,74,79,84,89],{"skillNo":62,"name":63,"nameZh":6,"description":64,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":65,"categories":66,"keywords":67,"publishedAt":68},"01M7BBJDYHJMGTJYSC37JVWY8S","i18n-layout","Text layout and encoding guidance: character encoding (UTF-8, legacy Korean code pages, BOM hazards), line endings, RTL\u002Fbidi handling, and script-specific font selection (Hangul focus). Use when: encoding is corrupted or mojibake appears, an RTL locale must render correctly, fonts must be chosen for a script, or CRLF\u002FBOM issues surface.","https:\u002F\u002Fgithub.com\u002F5throck\u002Fai-workspace-standards\u002Fblob\u002Fmain\u002Ftemplates\u002Fco-work\u002Fskills\u002Fi18n-layout\u002FSKILL.md",[],[],"2026-11-15 14:19:17",{"skillNo":70,"name":63,"nameZh":6,"description":64,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":71,"categories":72,"keywords":73,"publishedAt":68},"01M7BBJ9XHAAS1AVGKZZ841VBZ","https:\u002F\u002Fgithub.com\u002F5throck\u002Fai-workspace-standards\u002Fblob\u002Fmain\u002Ftemplates\u002Fco-work\u002F.hermes\u002Fskills\u002Fi18n-layout\u002FSKILL.md",[],[],{"skillNo":75,"name":63,"nameZh":6,"description":64,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":76,"categories":77,"keywords":78,"publishedAt":68},"01M7BBJ5C3X8TKFKG5R9P9P49W","https:\u002F\u002Fgithub.com\u002F5throck\u002Fai-workspace-standards\u002Fblob\u002Fmain\u002Ftemplates\u002Fco-work\u002F.gemini\u002Fskills\u002Fi18n-layout\u002FSKILL.md",[],[],{"skillNo":80,"name":63,"nameZh":6,"description":64,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":81,"categories":82,"keywords":83,"publishedAt":68},"01M7BBJ1B52X0QMJ2QVBMPJB37","https:\u002F\u002Fgithub.com\u002F5throck\u002Fai-workspace-standards\u002Fblob\u002Fmain\u002Ftemplates\u002Fco-work\u002F.codex\u002Fskills\u002Fi18n-layout\u002FSKILL.md",[],[],{"skillNo":85,"name":63,"nameZh":6,"description":64,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":86,"categories":87,"keywords":88,"publishedAt":68},"01M7BBHX91BW2Q2R276MRX5AW3","https:\u002F\u002Fgithub.com\u002F5throck\u002Fai-workspace-standards\u002Fblob\u002Fmain\u002Ftemplates\u002Fco-work\u002F.claude\u002Fskills\u002Fi18n-layout\u002FSKILL.md",[],[],{"skillNo":90,"name":63,"nameZh":6,"description":64,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":91,"categories":92,"keywords":93,"publishedAt":68},"01M7BBHQWGXPSFRWN1PRC2NMMV","https:\u002F\u002Fgithub.com\u002F5throck\u002Fai-workspace-standards\u002Fblob\u002Fmain\u002Ftemplates\u002Fco-work\u002F.agents\u002Fskills\u002Fi18n-layout\u002FSKILL.md",[],[]]