diff --git a/src/app/config.ts b/src/app/config.ts
index 7f52ab4c..483cac97 100644
--- a/src/app/config.ts
+++ b/src/app/config.ts
@@ -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;
diff --git a/src/cmdk/CommandKClient.tsx b/src/cmdk/CommandKClient.tsx
index 20b45801..a040071f 100644
--- a/src/cmdk/CommandKClient.tsx
+++ b/src/cmdk/CommandKClient.tsx
@@ -631,7 +631,7 @@ export default function CommandKClient({
key={heading}
heading={
diff --git a/src/components/ImageInput.tsx b/src/components/ImageInput.tsx
index 9b25ee3f..a16b6963 100644
--- a/src/components/ImageInput.tsx
+++ b/src/components/ImageInput.tsx
@@ -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,
diff --git a/src/i18n/index.ts b/src/i18n/index.ts
index ac4d4881..7ef7979b 100644
--- a/src/i18n/index.ts
+++ b/src/i18n/index.ts
@@ -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;
}
+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 = {
'pt-br': PT_BR,
'pt-pt': PT_PT,
@@ -15,17 +70,17 @@ export const LOCALE_TEXT: Record = {
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);
};
diff --git a/src/i18n/locales/pt-br.ts b/src/i18n/locales/pt-br.ts
index ab33517e..6573ad1e 100644
--- a/src/i18n/locales/pt-br.ts
+++ b/src/i18n/locales/pt-br.ts
@@ -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;
diff --git a/src/i18n/locales/pt-pt.ts b/src/i18n/locales/pt-pt.ts
index 39278750..334db3d9 100644
--- a/src/i18n/locales/pt-pt.ts
+++ b/src/i18n/locales/pt-pt.ts
@@ -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;
diff --git a/src/i18n/locales/us-en.ts b/src/i18n/locales/us-en.ts
index ee373834..6d1490d9 100644
--- a/src/i18n/locales/us-en.ts
+++ b/src/i18n/locales/us-en.ts
@@ -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;
diff --git a/src/photo/PhotoHeader.tsx b/src/photo/PhotoHeader.tsx
index 9f639099..7eec0d93 100644
--- a/src/photo/PhotoHeader.tsx
+++ b/src/photo/PhotoHeader.tsx
@@ -155,13 +155,13 @@ export default function PhotoHeader({
}} />}
>
:
- {APP_TEXT.utility.paginate(
+ {APP_TEXT.utility.paginateAction(
paginationIndex,
paginationCount,
entityVerb)}