Switch to template i18n strategy
This commit is contained in:
parent
0cffeeec1c
commit
878edc713d
@ -21,11 +21,11 @@ export const TEMPLATE_DESCRIPTION = 'Store photos with original camera data';
|
||||
export const TEMPLATE_REPO_OWNER = 'sambecker';
|
||||
export const TEMPLATE_REPO_NAME = 'exif-photo-blog';
|
||||
export const TEMPLATE_REPO_BRANCH = 'main';
|
||||
// eslint-disable-next-line max-len
|
||||
export const TEMPLATE_REPO_URL = `https://github.com/${TEMPLATE_REPO_OWNER}/${TEMPLATE_REPO_NAME}`;
|
||||
export const TEMPLATE_REPO_URL =
|
||||
`https://github.com/${TEMPLATE_REPO_OWNER}/${TEMPLATE_REPO_NAME}`;
|
||||
export const TEMPLATE_REPO_URL_FORK = `${TEMPLATE_REPO_URL}/fork`;
|
||||
// eslint-disable-next-line max-len
|
||||
export const TEMPLATE_REPO_URL_README = `${TEMPLATE_REPO_URL}?tab=readme-ov-file`;
|
||||
export const TEMPLATE_REPO_URL_README =
|
||||
`${TEMPLATE_REPO_URL}?tab=readme-ov-file`;
|
||||
|
||||
export const VERCEL_GIT_PROVIDER =
|
||||
process.env.NEXT_PUBLIC_VERCEL_GIT_PROVIDER;
|
||||
|
||||
@ -631,7 +631,7 @@ export default function CommandKClient({
|
||||
key={heading}
|
||||
heading={<div className={clsx(
|
||||
'flex items-center',
|
||||
'px-2 pt-1 pb-1.5',
|
||||
'px-2 py-1',
|
||||
'text-xs font-medium text-dim tracking-wider',
|
||||
isPending && 'opacity-20',
|
||||
)}>
|
||||
|
||||
@ -85,7 +85,7 @@ export default function ImageInput({
|
||||
>
|
||||
{isUploading
|
||||
? filesLength > 1
|
||||
? APP_TEXT.utility.paginate(
|
||||
? APP_TEXT.utility.paginateAction(
|
||||
fileUploadIndex + 1,
|
||||
filesLength,
|
||||
APP_TEXT.admin.uploading,
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import US_EN from './locales/us-en';
|
||||
import PT_BR from './locales/pt-br';
|
||||
import PT_PT from './locales/pt-pt';
|
||||
import { enUS, ptBR, pt } from 'date-fns/locale';
|
||||
|
||||
export type I18N = typeof US_EN;
|
||||
|
||||
@ -8,6 +9,60 @@ export type I18NDeepPartial = {
|
||||
[key in keyof I18N]?: Partial<I18N[key]>;
|
||||
}
|
||||
|
||||
const getDateFnLocale = (locale: string) => {
|
||||
switch (locale) {
|
||||
case 'pt-pt': return pt;
|
||||
case 'pt-br': return ptBR;
|
||||
default: return enUS;
|
||||
}
|
||||
};
|
||||
|
||||
const generateI18NWithFunctions = (i18nText: I18N) => {
|
||||
return {
|
||||
...i18nText,
|
||||
category: {
|
||||
...i18nText.category,
|
||||
cameraTitle: (camera: string) =>
|
||||
i18nText.category.cameraTitle.replace('{{camera}}', camera),
|
||||
cameraShare: (camera: string) =>
|
||||
i18nText.category.cameraShare.replace('{{camera}}', camera),
|
||||
taggedPhrase: (tag: string) =>
|
||||
i18nText.category.taggedPhrase.replace('{{tag}}', tag),
|
||||
recipeShare: (recipe: string) =>
|
||||
i18nText.category.recipeShare.replace('{{recipe}}', recipe),
|
||||
filmShare: (film: string) =>
|
||||
i18nText.category.filmShare.replace('{{film}}', film),
|
||||
focalLengthTitle: (focal: string) =>
|
||||
i18nText.category.focalLengthTitle.replace('{{focal}}', focal),
|
||||
focalLengthShare: (focal: string) =>
|
||||
i18nText.category.focalLengthShare.replace('{{focal}}', focal),
|
||||
},
|
||||
admin: {
|
||||
...i18nText.admin,
|
||||
deleteConfirm: (photoTitle: string) =>
|
||||
i18nText.admin.deleteConfirm.replace('{{photoTitle}}', photoTitle),
|
||||
},
|
||||
misc: {
|
||||
...i18nText.misc,
|
||||
copyPhrase: (label: string) =>
|
||||
i18nText.misc.copyPhrase.replace('{{label}}', label),
|
||||
},
|
||||
utility: {
|
||||
...i18nText.utility,
|
||||
paginate: (index: number, count: number) =>
|
||||
i18nText.utility.paginate
|
||||
.replace('{{index}}', index.toString())
|
||||
.replace('{{count}}', count.toString()),
|
||||
paginateAction: (index: number, count: number, action: string) =>
|
||||
i18nText.utility.paginateAction
|
||||
.replace('{{index}}', index.toString())
|
||||
.replace('{{count}}', count.toString())
|
||||
.replace('{{action}}', action),
|
||||
},
|
||||
dateLocale: getDateFnLocale(i18nText.locale),
|
||||
};
|
||||
};
|
||||
|
||||
export const LOCALE_TEXT: Record<string, I18NDeepPartial | undefined> = {
|
||||
'pt-br': PT_BR,
|
||||
'pt-pt': PT_PT,
|
||||
@ -15,17 +70,17 @@ export const LOCALE_TEXT: Record<string, I18NDeepPartial | undefined> = {
|
||||
|
||||
export const getTextForLocale = (
|
||||
locale = '',
|
||||
): I18N => {
|
||||
) => {
|
||||
const text = US_EN;
|
||||
|
||||
Object.entries(LOCALE_TEXT[locale.toLocaleLowerCase()] ?? {})
|
||||
.forEach(([key, value]) => {
|
||||
// Fall back to English for missing keys
|
||||
text[key as keyof I18N] = {
|
||||
...text[key as keyof I18N],
|
||||
...value,
|
||||
} as any;
|
||||
...text[key as keyof I18N] as any,
|
||||
...value as any,
|
||||
};
|
||||
});
|
||||
|
||||
return text;
|
||||
return generateI18NWithFunctions(text);
|
||||
};
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { I18NDeepPartial } from '..';
|
||||
import { ptBR } from 'date-fns/locale';
|
||||
|
||||
const TEXT: I18NDeepPartial = {
|
||||
locale: 'pt-br',
|
||||
photo: {
|
||||
photo: 'Foto',
|
||||
photoPlural: 'Fotos',
|
||||
@ -13,25 +13,25 @@ const TEXT: I18NDeepPartial = {
|
||||
category: {
|
||||
camera: 'Câmera',
|
||||
cameraPlural: 'Câmeras',
|
||||
cameraTitle: (camera: string) => `Tirado com ${camera}`,
|
||||
cameraShare: (camera: string) => `Fotos tiradas com ${camera}`,
|
||||
cameraTitle: 'Tirado com {{camera}}',
|
||||
cameraShare: 'Fotos tiradas com {{camera}}',
|
||||
lens: 'Lente',
|
||||
lensPlural: 'Lentes',
|
||||
tag: 'Tag',
|
||||
tagPlural: 'Tags',
|
||||
taggedPhotos: 'Fotos marcadas',
|
||||
taggedPhrase: (tag: string) => `Fotos marcadas com '${tag}'`,
|
||||
taggedPhrase: 'Fotos marcadas com {{tag}}',
|
||||
taggedFavs: 'Fotos favoritas',
|
||||
recipe: 'Receita',
|
||||
recipePlural: 'Receitas',
|
||||
recipeShare: (recipe: string) => `Fotos da receita ${recipe}`,
|
||||
recipeShare: 'Fotos da receita {{recipe}}',
|
||||
film: 'Filme',
|
||||
filmPlural: 'Filmes',
|
||||
filmShare: (film: string) => `Fotos tiradas com ${film}`,
|
||||
filmShare: 'Fotos tiradas com {{film}}',
|
||||
focalLength: 'Distância focal',
|
||||
focalLengthPlural: 'Distâncias focais',
|
||||
focalLengthTitle: (focal: string) => `Distância focal ${focal}`,
|
||||
focalLengthShare: (focal: string) => `Fotos tiradas em ${focal}`,
|
||||
focalLengthTitle: 'Distância focal {{focal}}',
|
||||
focalLengthShare: 'Fotos tiradas em {{focal}}',
|
||||
},
|
||||
nav: {
|
||||
home: 'Início',
|
||||
@ -93,8 +93,7 @@ const TEXT: I18NDeepPartial = {
|
||||
download: 'Baixar',
|
||||
sync: 'Sincronizar',
|
||||
delete: 'Excluir',
|
||||
deleteConfirm: (photoTitle: string) =>
|
||||
`Tem certeza de que deseja excluir "${photoTitle}"?`,
|
||||
deleteConfirm: 'Tem certeza de que deseja excluir "{{photoTitle}}"?',
|
||||
},
|
||||
onboarding: {
|
||||
setupComplete: 'Configuração concluída!',
|
||||
@ -109,18 +108,12 @@ const TEXT: I18NDeepPartial = {
|
||||
finishing: 'Finalizando ...',
|
||||
uploading: 'Enviando',
|
||||
repo: 'Feito com',
|
||||
copyPhrase: (label: string) => `${label} copiado`,
|
||||
copyPhrase: '{{label}} copiado',
|
||||
},
|
||||
utility: {
|
||||
paginate: (
|
||||
index: number,
|
||||
count: number,
|
||||
action?: string,
|
||||
) => action
|
||||
? `${action} ${index} de ${count}`
|
||||
: `${index} de ${count}`,
|
||||
paginate: '{{index}} de {{count}}',
|
||||
paginateAction: '{{action}} {{index}} de {{count}}',
|
||||
},
|
||||
dateLocale: ptBR,
|
||||
};
|
||||
|
||||
export default TEXT;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { I18NDeepPartial } from '..';
|
||||
import { pt } from 'date-fns/locale';
|
||||
|
||||
const TEXT: I18NDeepPartial = {
|
||||
locale: 'pt-pt',
|
||||
photo: {
|
||||
photo: 'Fotografia',
|
||||
photoPlural: 'Fotografias',
|
||||
@ -13,25 +13,25 @@ const TEXT: I18NDeepPartial = {
|
||||
category: {
|
||||
camera: 'Máquina Fotográfica',
|
||||
cameraPlural: 'Máquinas Fotográficas',
|
||||
cameraTitle: (camera: string) => `Tirado com ${camera}`,
|
||||
cameraShare: (camera: string) => `Fotografias tiradas com ${camera}`,
|
||||
cameraTitle: 'Tirado com {{camera}}',
|
||||
cameraShare: 'Fotografias tiradas com {{camera}}',
|
||||
lens: 'Objetiva',
|
||||
lensPlural: 'Objetivas',
|
||||
tag: 'Etiqueta',
|
||||
tagPlural: 'Etiquetas',
|
||||
taggedPhotos: 'Fotografias etiquetadas',
|
||||
taggedPhrase: (tag: string) => `Fotos etiquetadas com '${tag}'`,
|
||||
taggedPhrase: 'Fotos etiquetadas com {{tag}}',
|
||||
taggedFavs: 'Fotografias favoritas',
|
||||
recipe: 'Receita',
|
||||
recipePlural: 'Receitas',
|
||||
recipeShare: (recipe: string) => `Fotografias da receita ${recipe}`,
|
||||
recipeShare: 'Fotografias da receita {{recipe}}',
|
||||
film: 'Filme fotográfico',
|
||||
filmPlural: 'Filmes fotográficos',
|
||||
filmShare: (film: string) => `Fotografias tiradas com ${film}`,
|
||||
filmShare: 'Fotografias tiradas com {{film}}',
|
||||
focalLength: 'Distância focal',
|
||||
focalLengthPlural: 'Distâncias focais',
|
||||
focalLengthTitle: (focal: string) => `Distância focal ${focal}`,
|
||||
focalLengthShare: (focal: string) => `Fotos tiradas em ${focal}`,
|
||||
focalLengthTitle: 'Distância focal {{focal}}',
|
||||
focalLengthShare: 'Fotos tiradas em {{focal}}',
|
||||
},
|
||||
nav: {
|
||||
home: 'Início',
|
||||
@ -93,8 +93,7 @@ const TEXT: I18NDeepPartial = {
|
||||
download: 'Descarregar',
|
||||
sync: 'Sincronizar',
|
||||
delete: 'Excluir',
|
||||
deleteConfirm: (photoTitle: string) =>
|
||||
`Tens certeza de que deseja excluir "${photoTitle}"?`,
|
||||
deleteConfirm: 'Tens certeza de que deseja excluir "{{photoTitle}}"?',
|
||||
},
|
||||
onboarding: {
|
||||
setupComplete: 'Configuração concluída!',
|
||||
@ -109,18 +108,12 @@ const TEXT: I18NDeepPartial = {
|
||||
finishing: 'A finalizar ...',
|
||||
uploading: 'A enviar',
|
||||
repo: 'Feito com',
|
||||
copyPhrase: (label: string) => `${label} copiado`,
|
||||
copyPhrase: '{{label}} copiado',
|
||||
},
|
||||
utility: {
|
||||
paginate: (
|
||||
index: number,
|
||||
count: number,
|
||||
action?: string,
|
||||
) => action
|
||||
? `${action} ${index} de ${count}`
|
||||
: `${index} de ${count}`,
|
||||
paginate: '{{index}} de {{count}}',
|
||||
paginateAction: '{{action}} {{index}} de {{count}}',
|
||||
},
|
||||
dateLocale: pt,
|
||||
};
|
||||
|
||||
export default TEXT;
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { enUS } from 'date-fns/locale';
|
||||
|
||||
const TEXT = {
|
||||
locale: 'en-us',
|
||||
photo: {
|
||||
photo: 'Photo',
|
||||
photoPlural: 'Photos',
|
||||
@ -12,25 +11,25 @@ const TEXT = {
|
||||
category: {
|
||||
camera: 'Camera',
|
||||
cameraPlural: 'Cameras',
|
||||
cameraTitle: (camera: string) => `Shot on ${camera}`,
|
||||
cameraShare: (camera: string) => `Photos shot on ${camera}`,
|
||||
cameraTitle: 'Shot on {{camera}}',
|
||||
cameraShare: 'Photos shot on {{camera}}',
|
||||
lens: 'Lens',
|
||||
lensPlural: 'Lenses',
|
||||
tag: 'Tag',
|
||||
tagPlural: 'Tags',
|
||||
taggedPhotos: 'Tagged Photos',
|
||||
taggedPhrase: (tag: string) => `Photos tagged '${tag}'`,
|
||||
taggedPhrase: 'Photos tagged {{tag}}',
|
||||
taggedFavs: 'Favorite Photos',
|
||||
recipe: 'Recipe',
|
||||
recipePlural: 'Recipes',
|
||||
recipeShare: (recipe: string) => `${recipe} recipe photos`,
|
||||
recipeShare: '{{recipe}} recipe photos',
|
||||
film: 'Film',
|
||||
filmPlural: 'Films',
|
||||
filmShare: (film: string) => `Photos shot on ${film}`,
|
||||
filmShare: 'Photos shot on {{film}}',
|
||||
focalLength: 'Focal Length',
|
||||
focalLengthPlural: 'Focal Lengths',
|
||||
focalLengthTitle: (focal: string) => `Focal Length ${focal}`,
|
||||
focalLengthShare: (focal: string) => `Photos shot at ${focal}`,
|
||||
focalLengthTitle: 'Focal Length {{focal}}',
|
||||
focalLengthShare: 'Photos shot at {{focal}}',
|
||||
},
|
||||
nav: {
|
||||
home: 'Home',
|
||||
@ -92,8 +91,7 @@ const TEXT = {
|
||||
download: 'Download',
|
||||
sync: 'Sync',
|
||||
delete: 'Delete',
|
||||
deleteConfirm: (photoTitle: string) =>
|
||||
`Are you sure you want to delete "${photoTitle}?"`,
|
||||
deleteConfirm: 'Are you sure you want to delete "{{photoTitle}}?"',
|
||||
},
|
||||
onboarding: {
|
||||
setupComplete: 'Setup Complete!',
|
||||
@ -108,18 +106,12 @@ const TEXT = {
|
||||
finishing: 'Finishing ...',
|
||||
uploading: 'Uploading',
|
||||
repo: 'Made with',
|
||||
copyPhrase: (label: string) => `${label} copied`,
|
||||
copyPhrase: '{{label}} copied',
|
||||
},
|
||||
utility: {
|
||||
paginate: (
|
||||
index: number,
|
||||
count: number,
|
||||
action?: string,
|
||||
) => action
|
||||
? `${action} ${index} of ${count}`
|
||||
: `${index} of ${count}`,
|
||||
paginate: '{{index}} of {{count}}',
|
||||
paginateAction: '{{action}} {{index}} of {{count}}',
|
||||
},
|
||||
dateLocale: enUS,
|
||||
};
|
||||
|
||||
export default TEXT;
|
||||
|
||||
@ -155,13 +155,13 @@ export default function PhotoHeader({
|
||||
}} />}
|
||||
</>
|
||||
: <ResponsiveText
|
||||
shortText={APP_TEXT.utility.paginate(
|
||||
shortText={APP_TEXT.utility.paginateAction(
|
||||
paginationIndex,
|
||||
paginationCount,
|
||||
entityVerb,
|
||||
)}
|
||||
>
|
||||
{APP_TEXT.utility.paginate(
|
||||
{APP_TEXT.utility.paginateAction(
|
||||
paginationIndex,
|
||||
paginationCount,
|
||||
entityVerb)}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user