@@ -18,28 +18,85 @@ export const SOURCE = {
1818 label : 'English' ,
1919 /** Exonym, for prompts and reports written in English. */
2020 english : 'English' ,
21+ indexed : true ,
2122} ;
2223
23- /** @type {ReadonlyArray<{code: string, dir: string, label: string, english: string}> } */
24+ /**
25+ * `indexed: false` keeps a translation out of the index — `noindex` on its
26+ * pages, no hreflang or sitemap entry — while it stays built, linked from the
27+ * switcher and readable. Set from Search Console demand, Jun–Sep 2026
28+ * impressions: vi 17, ja 12, ru 11, es 4, fr 4, pt-BR 3, ko 2, zh-CN 1,
29+ * against 101 English; a locale earns `true` at 10. Eight LLM translations of
30+ * every page is the shape Google's scaled-content policy describes, and it
31+ * cost a sister site (x-pat.pages.dev) its whole index in Aug 2026.
32+ */
33+ /** @type {ReadonlyArray<{code: string, dir: string, label: string, english: string, indexed: boolean}> } */
2434export const LOCALES = [
25- { code : 'zh-CN' , dir : 'zh-cn' , label : '简体中文' , english : 'Chinese (Simplified)' } ,
26- { code : 'ja' , dir : 'ja' , label : '日本語' , english : 'Japanese' } ,
27- { code : 'ko' , dir : 'ko' , label : '한국어' , english : 'Korean' } ,
28- { code : 'ru' , dir : 'ru' , label : 'Русский' , english : 'Russian' } ,
29- { code : 'es' , dir : 'es' , label : 'Español' , english : 'Spanish' } ,
30- { code : 'pt-BR' , dir : 'pt-br' , label : 'Português (BR)' , english : 'Portuguese (Brazil)' } ,
31- { code : 'fr' , dir : 'fr' , label : 'Français' , english : 'French' } ,
32- { code : 'vi' , dir : 'vi' , label : 'Tiếng Việt' , english : 'Vietnamese' } ,
35+ {
36+ code : 'zh-CN' ,
37+ dir : 'zh-cn' ,
38+ label : '简体中文' ,
39+ english : 'Chinese (Simplified)' ,
40+ indexed : false ,
41+ } ,
42+ {
43+ code : 'ja' ,
44+ dir : 'ja' ,
45+ label : '日本語' ,
46+ english : 'Japanese' ,
47+ indexed : true ,
48+ } ,
49+ { code : 'ko' , dir : 'ko' , label : '한국어' , english : 'Korean' , indexed : false } ,
50+ {
51+ code : 'ru' ,
52+ dir : 'ru' ,
53+ label : 'Русский' ,
54+ english : 'Russian' ,
55+ indexed : true ,
56+ } ,
57+ {
58+ code : 'es' ,
59+ dir : 'es' ,
60+ label : 'Español' ,
61+ english : 'Spanish' ,
62+ indexed : false ,
63+ } ,
64+ {
65+ code : 'pt-BR' ,
66+ dir : 'pt-br' ,
67+ label : 'Português (BR)' ,
68+ english : 'Portuguese (Brazil)' ,
69+ indexed : false ,
70+ } ,
71+ {
72+ code : 'fr' ,
73+ dir : 'fr' ,
74+ label : 'Français' ,
75+ english : 'French' ,
76+ indexed : false ,
77+ } ,
78+ {
79+ code : 'vi' ,
80+ dir : 'vi' ,
81+ label : 'Tiếng Việt' ,
82+ english : 'Vietnamese' ,
83+ indexed : true ,
84+ } ,
3385] ;
3486
3587export const ALL_LOCALES = [ SOURCE , ...LOCALES ] ;
3688
89+ /** The locales a crawler is told about — see `indexed` above. */
90+ export const INDEXED_LOCALES = ALL_LOCALES . filter ( ( l ) => l . indexed ) ;
91+
3792export const CODES = LOCALES . map ( ( l ) => l . code ) ;
3893
3994/** Lookup accepting either spelling, so CLI args can be `pt-BR` or `pt-br`. */
4095export function findLocale ( input ) {
4196 const needle = String ( input ) . toLowerCase ( ) ;
42- return ALL_LOCALES . find ( ( l ) => l . code . toLowerCase ( ) === needle || l . dir === needle ) ;
97+ return ALL_LOCALES . find (
98+ ( l ) => l . code . toLowerCase ( ) === needle || l . dir === needle ,
99+ ) ;
43100}
44101
45102/**
@@ -63,6 +120,8 @@ export function localizedName(baseName, code) {
63120 */
64121export function switcherLine ( baseName , current ) {
65122 return ALL_LOCALES . map ( ( l ) =>
66- l . code === current ? l . label : `[${ l . label } ](./${ localizedName ( baseName , l . code ) } )` ,
123+ l . code === current
124+ ? l . label
125+ : `[${ l . label } ](./${ localizedName ( baseName , l . code ) } )` ,
67126 ) . join ( ' · ' ) ;
68127}
0 commit comments