Skip to content

Commit 39ee0bb

Browse files
committed
Lang _ to iso refactor
1 parent edf2b5f commit 39ee0bb

77 files changed

Lines changed: 253 additions & 249 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/energyvision/src/configs/satelliteConfig.ts

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,80 +2,73 @@
22
{
33
id: The key for this language
44
title: The title as it will be labeled in Sanity studio
5-
iso: Iso version of the language, used by Next.js localisation and react-intl
6-
name: Name as used in the Sanity localisation feature (this one is hard to explain :sweat_smile:)
7-
locale: The actual locale name as used by Next.js and locale folders/structure ([site]/locale)
5+
iso: ISO locale code (e.g., "en-GB"), used for document lang field and Next.js routing
6+
locale: Two-letter locale code (e.g., "en"), used for URL routing and next-intl config
87
}
98
*/
109
export type Language = {
1110
id: string
1211
title: string
1312
iso: string
14-
name: string
1513
locale: string
1614
}
1715
const languages = [
1816
{
1917
id: 'english',
2018
title: 'English (UK)',
2119
iso: 'en-GB',
22-
name: 'en_GB',
2320
locale: 'en',
2421
},
2522
{
2623
id: 'norwegian',
2724
title: 'Norwegian',
2825
iso: 'nb-NO',
29-
name: 'nb_NO',
3026
locale: 'no',
3127
},
3228
{
3329
id: 'portuguese',
3430
title: 'Portuguese (BR)',
3531
iso: 'pt-BR',
36-
name: 'pt_BR',
3732
locale: 'pt',
3833
},
39-
{ id: 'german', title: 'German', iso: 'de-DE', name: 'de_DE', locale: 'de' },
34+
{ id: 'german', title: 'German', iso: 'de-DE', locale: 'de' },
4035
{
4136
id: 'spanish-ar',
4237
title: 'Spanish',
4338
iso: 'es-AR',
44-
name: 'es_AR',
4539
locale: 'es',
4640
},
47-
{ id: 'polish', title: 'Polish', iso: 'pl-PL', name: 'pl_PL', locale: 'pl' },
41+
{ id: 'polish', title: 'Polish', iso: 'pl-PL', locale: 'pl' },
4842
{
4943
id: 'japanese',
5044
title: 'Japanese',
5145
iso: 'ja-JP',
52-
name: 'ja_JP',
5346
locale: 'ja',
5447
},
55-
{ id: 'korean', title: 'Korean', iso: 'ko-KR', name: 'ko_KR', locale: 'ko' },
56-
{ id: 'welsh', title: 'Welsh', iso: 'cy-CY', name: 'cy_CY', locale: 'cy' },
48+
{ id: 'korean', title: 'Korean', iso: 'ko-KR', locale: 'ko' },
49+
{ id: 'welsh', title: 'Welsh', iso: 'cy-CY', locale: 'cy' },
5750
]
5851

5952
/**
6053
* @type {Record<string, string>}
6154
*/
6255
export const newsSlug: Record<string, string> = {
63-
en_GB: 'news',
64-
nb_NO: 'nyheter',
65-
pt_BR: 'noticias',
66-
pl_PL: 'aktualnosci',
67-
de_DE: 'aktuelles',
68-
ja_JP: 'news',
69-
ko_KR: 'news',
70-
cy_CY: 'newyddion',
56+
'en-GB': 'news',
57+
'nb-NO': 'nyheter',
58+
'pt-BR': 'noticias',
59+
'pl-PL': 'aktualnosci',
60+
'de-DE': 'aktuelles',
61+
'ja-JP': 'news',
62+
'ko-KR': 'news',
63+
'cy-CY': 'newyddion',
7164
}
7265

7366
/**
7467
* @type {Record<string, string>}
7568
*/
7669
export const magazineSlug: Record<string, string> = {
77-
en_GB: 'magazine',
78-
nb_NO: 'magasin',
70+
'en-GB': 'magazine',
71+
'nb-NO': 'magasin',
7972
}
8073

8174
/*
@@ -187,9 +180,7 @@ const websiteDomains: Partial<
187180
/**
188181
* @returns {{
189182
* id: string
190-
* title: string
191183
* iso: string
192-
* name: string
193184
* locale: string
194185
* }[]}
195186
*/
@@ -206,7 +197,7 @@ const logAndFallback = (dataset: DatasetsKeys) => {
206197
}
207198

208199
export const localNewsTags: Record<string, string[]> = {
209-
en_GB: ['ev', 'uk', 'us'],
200+
'en-GB': ['ev', 'uk', 'us'],
210201
}
211202

212203
/**
@@ -234,3 +225,9 @@ export const getAllDomainUrls = () => {
234225
return Object.values(websiteDomains).map(dataset => dataset.url)
235226
//return Object.keys(datasets).map((dataset) => websiteDomains[dataset]?.url)
236227
}
228+
229+
/**
230+
* Converts ISO locale code to Sanity schema field name format
231+
* Example: "en-GB" → "en_GB", "nb-NO" → "nb_NO"
232+
*/
233+
export const isoToSchemaName = (iso: string): string => iso.replace('-', '_')

search/common/language.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ describe('Language function tests', () => {
66
const sut = languageFromIso
77

88
describe('With english iso code', () => {
9-
const english = { internalCode: 'en_GB', isoCode: 'en-GB' }
9+
const english = { internalCode: 'en-GB', isoCode: 'en-GB' }
1010
const res = sut('en-GB')
1111
it('english language object is returned', () => {
1212
E.foldW(

search/common/language.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ export type Language = {
77
isoCode: string
88
}
99

10-
const english = { internalCode: 'en_GB', isoCode: 'en-GB' }
11-
const norwegian = { internalCode: 'nb_NO', isoCode: 'nb-NO' }
10+
const english = { internalCode: 'en-GB', isoCode: 'en-GB' }
11+
const norwegian = { internalCode: 'nb-NO', isoCode: 'nb-NO' }
1212

1313
type LanguageMappingsType = Language[]
1414
const languageMappings: LanguageMappingsType = [english, norwegian]

studio/actions/CustomDuplicateAction.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export function createCustomDuplicateAction(originalAction: DocumentActionCompon
2121
return null
2222
}
2323

24-
if (lang == defaultLanguage.name) {
24+
if (lang == defaultLanguage.iso) {
2525
// allow duplicate action only on base language
2626
originalResult.onHandle && originalResult.onHandle()
2727
} else {

studio/actions/customDelete/DeleteTranslationAction.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export const DeleteTranslationAction: DocumentActionComponent = (props) => {
1616

1717
const doc = props.draft || props.published
1818
const documentLanguage = doc ? doc[languageField] : null
19-
const isDefaultLanguageDocument = defaultLanguage.name === documentLanguage
19+
const isDefaultLanguageDocument = defaultLanguage.iso === documentLanguage
2020

2121
const { id: documentId } = props
2222
const [isDialogOpen, setDialogOpen] = useState(false)

studio/actions/customDelete/components/DeleteTranslationDialog/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export default function DeleteTranslationDialog(props: DeleteTranslationDialogPr
6363

6464
return (
6565
<Stack space={4}>
66-
{translations && translations.length > 0 && doc.lang === defaultLanguage.name ? (
66+
{translations && translations.length > 0 && doc.lang === defaultLanguage.iso ? (
6767
<>
6868
<Text>Delete this document and its translations?</Text>
6969
{translatedDocs.length > 0 &&

studio/helpers/referenceFilters.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { SanityDocument } from 'sanity'
22
import { defaultLanguage } from '../languages'
33

4-
export const langOrDefault = (lang: string | unknown) => lang || defaultLanguage.name
4+
export const langOrDefault = (lang: string | unknown) => lang || defaultLanguage.iso
55

66
export const filterByLang = ({ document }: { document: SanityDocument }) => ({
77
filter: `lang == $lang`,

studio/initialValueTemplates.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import type { Template } from 'sanity'
2-
import { defaultLanguage, languages } from './languages'
2+
import { defaultLanguage, isoToSchemaName, languages } from './languages'
33
import textSnippets from './schemas/textSnippets'
4-
import { magazineSlug, newsSlug } from './sitesConfig'
54
import { Flags } from './src/lib/datasetHelpers'
65

76
const ParentRoutesTemplates: Template<any, any>[] = languages.map(
8-
({ name, title }) => ({
9-
id: `parent-route-${name}`,
7+
({ iso, title }) => ({
8+
id: `parent-route-${iso}`,
109
title: `Parent route - ${title}`,
11-
schemaType: `route_${name}`,
10+
schemaType: `route_${isoToSchemaName(iso)}`,
1211
parameters: [{ name: 'parentId', type: 'string' }],
1312
value: (params: Record<string, unknown>) => ({
1413
parent: { _type: 'reference', _ref: params.parentId },
@@ -24,8 +23,8 @@ const TextSnippetsTemplates: Template<any, any>[] = Object.keys(
2423
schemaType: `textSnippet`,
2524
parameters: [{ name: 'defaultValue', type: 'string' }],
2625
value: (params: Record<string, unknown>) => {
27-
const fields = languages.map(({ name }) => ({
28-
[name]: params.defaultValue,
26+
const fields = languages.map(({ iso }) => ({
27+
[isoToSchemaName(iso)]: params.defaultValue,
2928
}))
3029
return Object.assign({}, ...fields)
3130
},
@@ -94,7 +93,7 @@ const localNewsWithTagTemplate: Template<any, any> = {
9493
],
9594
value: (params: Record<string, unknown>) => ({
9695
localNewsTag: params.localNewsTag,
97-
lang: params.lang || defaultLanguage.name,
96+
lang: params.lang || defaultLanguage.iso,
9897
}),
9998
}
10099

studio/languages.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import {
22
defaultWebLanguage,
33
getLanguages,
4+
isoToSchemaName,
45
} from '@energyvision/shared/satelliteConfig'
56
import { dataset } from './sanity.client'
67

8+
export { isoToSchemaName }
79
export const languages = getLanguages(dataset)
810

911
export const defaultLanguage = languages[0]
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { at, defineMigration, set } from 'sanity/migrate'
2+
3+
/**
4+
* Migrates all documents' `lang` field from underscore format (e.g. "en_GB")
5+
* to ISO hyphen format (e.g. "en-GB").
6+
*
7+
* Also updates the `language` field inside `translation.metadata` translations
8+
* arrays, which was added by the i18n-doc-v6 migration.
9+
*
10+
* Steps:
11+
* 1. Backup: pnpm sanity dataset export <dataset>
12+
* 2. Dry run: pnpm sanity migration run lang-underscore-to-hyphen --project=<PROJECT_ID> --dataset=<DATASET>
13+
* 3. Migrate: pnpm sanity migration run lang-underscore-to-hyphen --project=<PROJECT_ID> --dataset=<DATASET> --no-dry-run
14+
*
15+
* Run against every dataset:
16+
* global, global-development, brazil, germany, argentina, poland,
17+
* japan, southkorea, celticsea, sponsorship, equinorfunds, storage, secret
18+
*/
19+
20+
const LANG_REGEX = /^[a-z]{2}_[A-Z]{2}$/
21+
22+
const toIso = (lang: string) => lang.replace('_', '-')
23+
24+
export default defineMigration({
25+
title: 'lang underscore → hyphen (en_GB → en-GB)',
26+
27+
migrate: {
28+
document(doc, _context) {
29+
const patches = []
30+
31+
// 1. Update top-level `lang` field on any document that has it
32+
if (typeof doc.lang === 'string' && LANG_REGEX.test(doc.lang)) {
33+
patches.push(at('lang', set(toIso(doc.lang))))
34+
}
35+
36+
// 2. Update `language` field inside translation.metadata translations array
37+
if (doc._type === 'translation.metadata' && Array.isArray(doc.translations)) {
38+
;(doc.translations as Array<{ _key: string; language?: string }>).forEach((item, index) => {
39+
if (typeof item.language === 'string' && LANG_REGEX.test(item.language)) {
40+
patches.push(at(`translations[${index}].language`, set(toIso(item.language))))
41+
}
42+
// Also update _key if it matches the old format
43+
if (typeof item._key === 'string' && LANG_REGEX.test(item._key)) {
44+
patches.push(at(`translations[${index}]._key`, set(toIso(item._key))))
45+
}
46+
})
47+
}
48+
49+
return patches.length > 0 ? patches : undefined
50+
},
51+
},
52+
})

0 commit comments

Comments
 (0)