diff --git a/app/BudgetIntent/en.lproj/InfoPlist.strings b/app/BudgetIntent/en.lproj/InfoPlist.strings
new file mode 100644
index 0000000..6db7565
--- /dev/null
+++ b/app/BudgetIntent/en.lproj/InfoPlist.strings
@@ -0,0 +1,2 @@
+"CFBundleDisplayName" = "BudgetIntent";
+"CFBundleName" = "BudgetIntent";
diff --git a/app/BudgetIntent/pt-BR.lproj/InfoPlist.strings b/app/BudgetIntent/pt-BR.lproj/InfoPlist.strings
new file mode 100644
index 0000000..2493437
--- /dev/null
+++ b/app/BudgetIntent/pt-BR.lproj/InfoPlist.strings
@@ -0,0 +1,2 @@
+"CFBundleDisplayName" = "Orçamentos do Dime";
+"CFBundleName" = "Orçamentos do Dime";
diff --git a/app/BudgetIntentUI/en.lproj/InfoPlist.strings b/app/BudgetIntentUI/en.lproj/InfoPlist.strings
new file mode 100644
index 0000000..4472a08
--- /dev/null
+++ b/app/BudgetIntentUI/en.lproj/InfoPlist.strings
@@ -0,0 +1,2 @@
+"CFBundleDisplayName" = "BudgetIntentUI";
+"CFBundleName" = "BudgetIntentUI";
diff --git a/app/BudgetIntentUI/pt-BR.lproj/InfoPlist.strings b/app/BudgetIntentUI/pt-BR.lproj/InfoPlist.strings
new file mode 100644
index 0000000..2493437
--- /dev/null
+++ b/app/BudgetIntentUI/pt-BR.lproj/InfoPlist.strings
@@ -0,0 +1,2 @@
+"CFBundleDisplayName" = "Orçamentos do Dime";
+"CFBundleName" = "Orçamentos do Dime";
diff --git a/app/ExpenditureWidget/BudgetWidget.swift b/app/ExpenditureWidget/BudgetWidget.swift
index 2084924..f3761bc 100644
--- a/app/ExpenditureWidget/BudgetWidget.swift
+++ b/app/ExpenditureWidget/BudgetWidget.swift
@@ -125,7 +125,7 @@ struct BudgetWidgetEntryView: View {
case 4:
return String(localized: "this year")
default:
- return "this week"
+ return String(localized: "this week")
}
}
diff --git a/app/ExpenditureWidget/LockBudgetWidget.swift b/app/ExpenditureWidget/LockBudgetWidget.swift
index 3555cd4..78b9847 100644
--- a/app/ExpenditureWidget/LockBudgetWidget.swift
+++ b/app/ExpenditureWidget/LockBudgetWidget.swift
@@ -136,7 +136,7 @@ struct LockBudgetWidgetEntryView: View {
case 4:
return String(localized: "this year")
default:
- return "this week"
+ return String(localized: "this week")
}
}
diff --git a/app/ExpenditureWidget/MainBudgetWidget.swift b/app/ExpenditureWidget/MainBudgetWidget.swift
index ad62635..ed1621a 100644
--- a/app/ExpenditureWidget/MainBudgetWidget.swift
+++ b/app/ExpenditureWidget/MainBudgetWidget.swift
@@ -92,7 +92,7 @@ struct MainBudgetWidgetEntryView: View {
case 4:
return String(localized: "this year")
default:
- return "this week"
+ return String(localized: "this week")
}
}
diff --git a/app/ExpenditureWidget/en.lproj/InfoPlist.strings b/app/ExpenditureWidget/en.lproj/InfoPlist.strings
new file mode 100644
index 0000000..f65a96e
--- /dev/null
+++ b/app/ExpenditureWidget/en.lproj/InfoPlist.strings
@@ -0,0 +1,2 @@
+"CFBundleDisplayName" = "ExpenditureWidgetExtension";
+"CFBundleName" = "ExpenditureWidgetExtension";
diff --git a/app/ExpenditureWidget/pt-BR.lproj/InfoPlist.strings b/app/ExpenditureWidget/pt-BR.lproj/InfoPlist.strings
new file mode 100644
index 0000000..3a84798
--- /dev/null
+++ b/app/ExpenditureWidget/pt-BR.lproj/InfoPlist.strings
@@ -0,0 +1,2 @@
+"CFBundleDisplayName" = "Widgets do Dime";
+"CFBundleName" = "Widgets do Dime";
diff --git a/app/ExpenditureWidget/pt-BR.lproj/WidgetConfiguration.strings b/app/ExpenditureWidget/pt-BR.lproj/WidgetConfiguration.strings
new file mode 100644
index 0000000..8a75572
--- /dev/null
+++ b/app/ExpenditureWidget/pt-BR.lproj/WidgetConfiguration.strings
@@ -0,0 +1,101 @@
+"0S0EUc" = "Ano";
+
+"1RQFcH-DGV4UF" = "Só para confirmar, você queria ‘Ano’?";
+
+"1RQFcH-P3jTfV" = "Só para confirmar, você queria ‘Dia’?";
+
+"1RQFcH-czRaIN" = "Só para confirmar, você queria ‘Mês’?";
+
+"1RQFcH-kmTpVR" = "Só para confirmar, você queria ‘Semana’?";
+
+"1hyBus" = "Configuração do widget de orçamento";
+
+"6cmEVw" = "Saldo total";
+
+"7qqVwM" = "Configuração do widget de transações recentes";
+
+"AUFESp" = "Configuração do widget de análises";
+
+"Bhhyri" = "Semana";
+
+"DGV4UF" = "Ano";
+
+"Eh1Ri6-DGV4UF" = "Há ${count} opções correspondentes a ‘Ano’.";
+
+"Eh1Ri6-P3jTfV" = "Há ${count} opções correspondentes a ‘Dia’.";
+
+"Eh1Ri6-czRaIN" = "Há ${count} opções correspondentes a ‘Mês’.";
+
+"Eh1Ri6-kmTpVR" = "Há ${count} opções correspondentes a ‘Semana’.";
+
+"H5x4UP-6cmEVw" = "Há ${count} opções correspondentes a ‘Saldo total’.";
+
+"H5x4UP-YcEMd2" = "Há ${count} opções correspondentes a ‘Total de despesas’.";
+
+"H5x4UP-mM5dSQ" = "Há ${count} opções correspondentes a ‘Receita total’.";
+
+"Ho0bYB" = "Período das análises";
+
+"JAwE5i-ZNKfLE" = "Há ${count} opções correspondentes a ‘Despesas’.";
+
+"JAwE5i-qZQiJe" = "Há ${count} opções correspondentes a ‘Receita’.";
+
+"OIASDL-ZNKfLE" = "Só para confirmar, você queria ‘Despesas’?";
+
+"OIASDL-qZQiJe" = "Só para confirmar, você queria ‘Receita’?";
+
+"P3jTfV" = "Dia";
+
+"QBbDzN" = "Receita";
+
+"QEV7yi" = "Widget de orçamento";
+
+"XTKaD2" = "Mês";
+
+"XlOqjc" = "Período";
+
+"YQ1Wnb" = "Período";
+
+"YcEMd2" = "Total de despesas";
+
+"ZNKfLE" = "Despesas";
+
+"Za14jD" = "Orçamento";
+
+"czRaIN" = "Mês";
+
+"e1simm-DGV4UF" = "Há ${count} opções correspondentes a ‘Ano’.";
+
+"e1simm-P3jTfV" = "Há ${count} opções correspondentes a ‘Dia’.";
+
+"e1simm-czRaIN" = "Há ${count} opções correspondentes a ‘Mês’.";
+
+"e1simm-kmTpVR" = "Há ${count} opções correspondentes a ‘Semana’.";
+
+"eeVlqE" = "Tipo de análise";
+
+"gBvLZr" = "Período";
+
+"iDgY1G-DGV4UF" = "Só para confirmar, você queria ‘Ano’?";
+
+"iDgY1G-P3jTfV" = "Só para confirmar, você queria ‘Dia’?";
+
+"iDgY1G-czRaIN" = "Só para confirmar, você queria ‘Mês’?";
+
+"iDgY1G-kmTpVR" = "Só para confirmar, você queria ‘Semana’?";
+
+"kmTpVR" = "Semana";
+
+"mM5dSQ" = "Receita total";
+
+"ocCluD-6cmEVw" = "Só para confirmar, você queria ‘Saldo total’?";
+
+"ocCluD-YcEMd2" = "Só para confirmar, você queria ‘Total de despesas’?";
+
+"ocCluD-mM5dSQ" = "Só para confirmar, você queria ‘Receita total’?";
+
+"qZQiJe" = "Receita";
+
+"wfQ8VF" = "Tipo de análise";
+
+"zlEWQ3" = "Tipo de análise";
diff --git a/app/Localizations/en.lproj/AppShortcuts.strings b/app/Localizations/en.lproj/AppShortcuts.strings
new file mode 100644
index 0000000..1352d77
--- /dev/null
+++ b/app/Localizations/en.lproj/AppShortcuts.strings
@@ -0,0 +1,3 @@
+"Extract leftover amount for your budgets in ${applicationName}" = "Extract leftover amount for your budgets in ${applicationName}";
+"Get insights in ${applicationName}" = "Get insights in ${applicationName}";
+"Log a new transaction in ${applicationName}" = "Log a new transaction in ${applicationName}";
diff --git a/app/Localizations/en.lproj/InfoPlist.strings b/app/Localizations/en.lproj/InfoPlist.strings
new file mode 100644
index 0000000..1a23e72
--- /dev/null
+++ b/app/Localizations/en.lproj/InfoPlist.strings
@@ -0,0 +1,6 @@
+"Add Expense" = "Add Expense";
+"CFBundleDisplayName" = "Dime";
+"CFBundleName" = "dime";
+"NSFaceIDUsageDescription" = "We need to unlock your data.";
+"NSPhotoLibraryAddUsageDescription" = "Save an image of a transaction for sharing.";
+"Search Entries" = "Search Entries";
diff --git a/app/Localizations/pt-BR.lproj/AppShortcuts.strings b/app/Localizations/pt-BR.lproj/AppShortcuts.strings
new file mode 100644
index 0000000..009ec90
--- /dev/null
+++ b/app/Localizations/pt-BR.lproj/AppShortcuts.strings
@@ -0,0 +1,3 @@
+"Extract leftover amount for your budgets in ${applicationName}" = "Consultar o valor restante dos seus orçamentos no ${applicationName}";
+"Get insights in ${applicationName}" = "Consultar análises no ${applicationName}";
+"Log a new transaction in ${applicationName}" = "Registrar um novo lançamento no ${applicationName}";
diff --git a/app/Localizations/pt-BR.lproj/InfoPlist.strings b/app/Localizations/pt-BR.lproj/InfoPlist.strings
new file mode 100644
index 0000000..2b02e0c
--- /dev/null
+++ b/app/Localizations/pt-BR.lproj/InfoPlist.strings
@@ -0,0 +1,6 @@
+"Add Expense" = "Adicionar despesa";
+"CFBundleDisplayName" = "Dime";
+"CFBundleName" = "dime";
+"NSFaceIDUsageDescription" = "O Face ID é usado para desbloquear e proteger seus dados.";
+"NSPhotoLibraryAddUsageDescription" = "Permite salvar uma imagem do lançamento para compartilhamento.";
+"Search Entries" = "Buscar lançamentos";
diff --git a/app/Localizations/pt-BR.lproj/Localizable.strings b/app/Localizations/pt-BR.lproj/Localizable.strings
new file mode 100644
index 0000000..b57298d
--- /dev/null
+++ b/app/Localizations/pt-BR.lproj/Localizable.strings
@@ -0,0 +1,533 @@
+/*
+ Localizable.strings
+ dime
+
+ Brazilian Portuguese localization
+*/
+
+// welcome sheet
+
+"dime_name" = "Dime";
+"welcome_header_1" = "Acompanhe suas finanças";
+"welcome_subtitle_1" = "Adicione novos lançamentos de forma simples e direta";
+"welcome_header_2" = "Analise suas despesas";
+"welcome_subtitle_2" = "Entenda seus gastos ao longo de diferentes períodos";
+"welcome_header_3" = "Mantenha-se dentro do orçamento";
+"welcome_subtitle_3" = "Defina metas por categoria e período para limitar seus gastos";
+"Get Started" = "Começar";
+
+// categories
+
+"Categories" = "Categorias";
+"no_income_categories" = "Nenhuma categoria de receita encontrada. Toque no botão 'Nova' para adicionar uma";
+"no_expense_categories" = "Nenhuma categoria de despesa encontrada. Toque no botão 'Nova' para adicionar uma";
+"Suggestions Hidden" = "Sugestões ocultas";
+"Successfully Edited" = "Editado com sucesso";
+"INCOME CATEGORIES" = "CATEGORIAS DE RECEITA";
+"EXPENSE CATEGORIES" = "CATEGORIAS DE DESPESA";
+"SUGGESTED" = "SUGESTÕES";
+"Income Category" = "Categoria de receita";
+"Expense Category" = "Categoria de despesa";
+"New" = "Nova";
+"Expense" = "Despesa";
+"Income" = "Receita";
+"Delete" = "Excluir";
+"Cancel" = "Cancelar";
+"Delete '%@'?" = "Excluir '%@'?";
+"This action cannot be undone, and all %@ transactions would be deleted." = "Esta ação não pode ser desfeita, e todas as transações de %@ serão excluídas.";
+"Category Name" = "Nome da categoria";
+"Missing Name" = "Nome ausente";
+"Missing Emoji" = "Emoji ausente";
+"Incomplete Entry" = "Lançamento incompleto";
+"Missing Information" = "Informações ausentes";
+"This action cannot be undone." = "Esta ação não pode ser desfeita.";
+"Duplicate Found" = "Item duplicado";
+"Please Edit Accordingly" = "Edite conforme necessário";
+"Please Change Emoji" = "Altere o emoji";
+"Please Change Name" = "Altere o nome";
+"Food" = "Alimentação";
+"Transport" = "Transporte";
+"Rent" = "Aluguel";
+"Subscriptions" = "Assinaturas";
+"Groceries" = "Supermercado";
+"Family" = "Família";
+"Utilities" = "Contas";
+"Fashion" = "Moda";
+"Healthcare" = "Saúde";
+"Pets" = "Animais de estimação";
+"Sneakers" = "Tênis";
+"Gifts" = "Presentes";
+"Paycheck" = "Salário";
+"Allowance" = "Mesada";
+"Part-Time" = "Trabalho de meio período";
+"Investments" = "Investimentos";
+"Tips" = "Gorjetas";
+"Successfully Added" = "Adicionado com sucesso";
+
+// new transaction page
+"Today, %@" = "Hoje, %@";
+"Add Note" = "Adicionar observação";
+"Category" = "Categoria";
+"none" = "nenhuma";
+"daily" = "diariamente";
+"weekly" = "semanalmente";
+"monthly" = "mensalmente";
+"custom" = "personalizado";
+"Custom Interval" = "Intervalo personalizado";
+"Repeats every" = "Repete a cada";
+"days" = "dias";
+"weeks" = "semanas";
+"months" = "meses";
+"Edit" = "Editar";
+"Delete Expense?" = "Excluir despesa?";
+"Missing Amount" = "Valor ausente";
+"Missing Category" = "Categoria ausente";
+"transaction-view-income-picker" = "Receita";
+
+// log view
+"Your Log is Empty" = "Seu histórico está vazio";
+"Press the plus button to add your first entry" = "Toque no botão de mais para adicionar seu primeiro lançamento";
+"Search entry by note" = "Buscar lançamento pela observação";
+"all entries" = "todos os lançamentos";
+"by type" = "por tipo";
+"by day" = "por dia";
+"by week" = "por semana";
+"by month" = "por mês";
+"by category" = "por categoria";
+"recurring" = "recorrentes";
+"filter-tag-type" = "por tipo";
+"filter-tag-day" = "por dia";
+"filter-tag-category" = "por categoria";
+"filter-tag-week" = "por semana";
+"filter-tag-month" = "por mês";
+"filter-tag-recurring" = "recorrentes";
+"filter-picker-income" = "Receita";
+"filter-tag-upcoming" = "futuros";
+"Total Spent" = "Total gasto";
+"Total Income" = "Receita total";
+"Net Total" = "Saldo total";
+"Net total" = "Saldo total";
+"Spent" = "Gasto";
+"Earned" = "Recebido";
+"today" = "hoje";
+"this week" = "esta semana";
+"this month" = "este mês";
+"this year" = "este ano";
+"No entries found." = "Nenhum lançamento encontrado.";
+"Try a different search query!" = "Tente fazer outra busca!";
+"yesterday" = "ontem";
+
+
+// insights
+"Insights" = "Análises";
+"Analyse Your Expenditure" = "Analise suas despesas";
+"As transactions start piling up" = "Conforme suas transações forem se acumulando";
+"Expenses" = "Despesas";
+"SPENT/DAY" = "GASTO/DIA";
+"INCOME/DAY" = "RECEITA/DIA";
+"SPENT/MTH" = "GASTO/MÊS";
+"INCOME/MTH" = "RECEITA/MÊS";
+"AVG/DAY" = "MÉDIA/DIA";
+"AVG/MTH" = "MÉDIA/MÊS";
+"That's all, buddy." = "Isso é tudo.";
+"Into the unknown." = "Rumo ao desconhecido.";
+"week" = "semana";
+"month" = "mês";
+"year" = "ano";
+"Jan" = "Jan";
+"Apr" = "Abr";
+"Jul" = "Jul";
+"Oct" = "Out";
+
+// budgets
+"Budgets" = "Orçamentos";
+"Budget Your Finances" = "Planeje suas finanças";
+"Link budgets to categories and set appropriate expenditure goals" = "Vincule orçamentos a categorias e defina metas de gastos adequadas";
+"No Budgets Found" = "Nenhum orçamento encontrado";
+"Add your first budget today!" = "Adicione seu primeiro orçamento hoje!";
+"category budget" = "orçamento por categoria";
+"overall budget" = "orçamento geral";
+"new" = "novo";
+"New Budget" = "Novo orçamento";
+"Overall Budget" = "Orçamento geral";
+"Select a category" = "Selecione uma categoria";
+"Begin by linking this budget to an existing category." = "Comece vinculando este orçamento a uma categoria existente.";
+"Choose a time frame" = "Escolha um período";
+"The budget will periodically refresh according to your preference." = "O orçamento será renovado periodicamente de acordo com sua preferência.";
+"Continue" = "Continuar";
+"Pick a start date" = "Escolha uma data de início";
+"Daily" = "Diário";
+"Weekly" = "Semanal";
+"Monthly" = "Mensal";
+"Yearly" = "Anual";
+"Which day of the %@ do you want your budget to start from?" = "Em qual dia de %@ você quer iniciar seu orçamento?";
+"weekNewBudget" = "cada semana";
+"monthNewBudget" = "cada mês";
+"yearNewBudget" = "cada ano";
+"Sunday" = "Domingo";
+"Monday" = "Segunda-feira";
+"Tuesday" = "Terça-feira";
+"Wednesday" = "Quarta-feira";
+"Thursday" = "Quinta-feira";
+"Friday" = "Sexta-feira";
+"Saturday" = "Sábado";
+"Start of month" = "Início do mês";
+"%@ of month" = "Dia %@ do mês";
+"Set budget amount" = "Defina o valor do orçamento";
+"Feel free to edit this in the future." = "Você poderá editar isso depois.";
+"%@ SPENT" = "%@ GASTO";
+"left %@" = "restante: %@";
+"over %@" = "excedido: %@";
+"left today" = "restante hoje";
+"left on %@" = "restante em %@";
+"over today" = "excedido hoje";
+"over on %@" = "excedido em %@";
+"left this week" = "restante esta semana";
+"over this week" = "excedido esta semana";
+"left each day" = "restante por dia";
+"left this month" = "restante este mês";
+"over this month" = "excedido este mês";
+"left this year" = "restante este ano";
+"over this year" = "excedido este ano";
+"%lldd left" = "%lldd restantes";
+"%lldh left" = "%lldh restantes";
+"%@ • %@ spent" = "%@ • %@ gasto";
+"Back" = "Voltar";
+"Delete the '%@' budget?" = "Excluir o orçamento '%@'?";
+"OVERALL SPENT: %@" = "TOTAL GASTO: %@";
+"Delete your overall budget?" = "Excluir seu orçamento geral?";
+
+// Settings
+"Settings" = "Ajustes";
+"GENERAL" = "GERAL";
+"DATA" = "DADOS";
+"OTHERS" = "OUTROS";
+"Appearance" = "Aparência";
+"Start of Week" = "Início da semana";
+"Notifications" = "Notificações";
+"Currency" = "Moeda";
+"Number Entry" = "Entrada de números";
+"Authentication" = "Autenticação";
+"Income Tracking" = "Acompanhamento de receitas";
+"Display Cents" = "Exibir centavos";
+"iCloud Sync" = "Sincronização com o iCloud";
+"Export Data" = "Exportar dados";
+"Erase Data" = "Apagar dados";
+"Animated Charts" = "Gráficos animados";
+"Feature Lab" = "Laboratório de recursos";
+"Tip Jar" = "Contribua";
+"Report Bug" = "Relatar problema";
+"Rate on App Store" = "Avaliar na App Store";
+"Share with Friends" = "Compartilhar com amigos";
+"Follow Dime on Twitter" = "Seguir o Dime no Twitter";
+"Follow Rafael on Instagram" = "Seguir o Rafael no Instagram";
+"Light" = "Claro";
+"Dark" = "Escuro";
+"System" = "Sistema";
+"Mornings" = "Manhãs";
+"Evenings" = "Noites";
+"Custom" = "Personalizado";
+"Off" = "Desativado";
+"On" = "Ativado";
+"Type 1" = "Tipo 1";
+"Type 2" = "Tipo 2";
+"Close and reload app for change to take effect." = "Feche e abra novamente o app para aplicar a alteração.";
+"Enable Notifications" = "Ativar notificações";
+"Every morning (8:00 AM)" = "Todas as manhãs (08:00)";
+"Every evening (8:00 PM)" = "Todas as noites (20:00)";
+"Custom Time" = "Horário personalizado";
+"Currencies" = "Moedas";
+"Number Entry Method" = "Método de entrada de números";
+"\"Pre-dotted\"" = "\"Centavos automáticos\"";
+"If you're too lazy to add a decimal point, I gotchu covered." = "Se você não quiser digitar a vírgula decimal, a gente cuida disso.";
+"\"Cent-less\"" = "\"Sem centavos\"";
+"If your transactions usually amount to whole numbers - this one is for you." = "Se suas transações geralmente têm valores inteiros, esta opção é para você.";
+"Enable Sync" = "Ativar sincronização";
+"Permanently Delete Everythin'" = "Apagar tudo permanentemente";
+"This action would delete all existing transactions, categories, and budgets, and cannot be undone." = "Esta ação excluirá todas as transações, categorias e orçamentos existentes e não poderá ser desfeita.";
+"Danger Zone" = "Zona de perigo";
+"This action genuinely cannot be undone. Long press to confirm." = "Esta ação realmente não pode ser desfeita. Mantenha pressionado para confirmar.";
+"Delete Literally Everything" = "Excluir literalmente tudo";
+"Back Out" = "Voltar atrás";
+"Celebrate Expenses" = "Comemorar despesas";
+"Show Line Graph" = "Exibir gráfico de linhas";
+"Budget Rows" = "Linhas de orçamento";
+"Experimental features - proceed with caution." = "Recursos experimentais — use com cuidado.";
+"Replace Time Label" = "Substituir horário";
+"Swaps the time label of each transaction with its category name. However, if you do not manually input a note for each transaction - in which case the note is the category name by default - duplicate text will appear." = "Substitui o horário de cada transação pelo nome da categoria. Porém, se você não inserir manualmente uma observação em cada transação — caso em que o nome da categoria é usado por padrão — aparecerá um texto duplicado.";
+"Keep the streak going!" = "Mantenha a sequência!";
+"Remember to input your expenses today." = "Lembre-se de registrar suas despesas hoje.";
+"Loading" = "Carregando";
+"Unable to load tip options, please try again later 🥲" = "Não foi possível carregar as opções de contribuição. Tente novamente mais tarde 🥲";
+"Hey! Dime was built by a solo student developer, and is intended to be completely free-of-charge, with no paywalls or ads. If you enjoy using Dime and want to support development, please consider a small tip." = "Olá! O Dime foi criado por um único desenvolvedor estudante e foi pensado para ser totalmente gratuito, sem conteúdo pago nem anúncios. Se você gosta de usar o Dime e quer apoiar o desenvolvimento, considere fazer uma pequena contribuição.";
+"Tip failed to go through, please try again!" = "Não foi possível concluir a contribuição. Tente novamente!";
+"Thanks a million, %@ Rafael" = "Muito obrigado, %@ Rafael";
+"Have a great day ahead!" = "Tenha um ótimo dia!";
+"Version %@ (%@)" = "Versão %@ (%@)";
+"Made with ❤️ by %@ from 🇸🇬" = "Feito com ❤️ por %@, de 🇸🇬";
+"☕ Coffee-Sized Tip" = "☕ Contribuição do tamanho de um café";
+"🌮 Taco-Sized Tip" = "🌮 Contribuição do tamanho de um taco";
+"🍕 Pizza-Sized Tip" = "🍕 Contribuição do tamanho de uma pizza";
+
+// Widgets
+
+// Labels
+"Recent Transactions" = "Transações recentes";
+"View your latest expenses." = "Veja suas despesas mais recentes.";
+"Analyse your expenditure breakdowns over various time periods." = "Analise a distribuição das suas despesas em diferentes períodos.";
+"Monitor how you are sticking to your overall budgets." = "Acompanhe seu progresso no orçamento geral.";
+"Budget" = "Orçamento";
+"Monitor how you are sticking to your budgets." = "Acompanhe seu progresso nos orçamentos.";
+"New Expense" = "Nova despesa";
+"A convenient button to log new purchases." = "Um botão prático para registrar novas compras.";
+
+"%lld%% spent" = "%lld%% gasto";
+"NO RECENT EXPENSES" = "NENHUMA DESPESA RECENTE";
+"RECENT EXPENSES" = "DESPESAS RECENTES";
+"in %@" = "em %@";
+"net" = "saldo";
+"earned" = "recebido";
+"spent" = "gasto";
+"Time Period" = "Período";
+"NO TRANSACTIONS\n%@" = "NENHUMA TRANSAÇÃO\n%@";
+"THIS WEEK" = "ESTA SEMANA";
+"THIS MONTH" = "ESTE MÊS";
+"THIS YEAR" = "ESTE ANO";
+"EARNED " = "RECEBIDO ";
+"SPENT " = "GASTO ";
+"ADD OVERALL BUDGET" = "ADICIONAR ORÇAMENTO GERAL";
+"Percent Spent" = "Percentual gasto";
+"Create your overall budget in the app" = "Crie seu orçamento geral no app";
+"ADD BUDGET" = "ADICIONAR ORÇAMENTO";
+"over" = "excedido";
+"SPENT: %@" = "GASTO: %@";
+"Select budget in widget options" = "Selecione um orçamento nas opções do widget";
+"Budget no longer exists - please select new budget from widget options." = "Este orçamento não existe mais. Selecione outro nas opções do widget.";
+"left" = "restante";
+"SELECT BUDGET" = "SELECIONAR ORÇAMENTO";
+"SELECT BUDGET IN WIDGET OPTIONS" = "SELECIONE UM ORÇAMENTO NAS OPÇÕES DO WIDGET";
+
+// Source strings added after the original localization pass
+
+"%.0f%%" = "%.0f%%";
+"%.2f" = "%.2f";
+"%@ %@" = "%@ %@";
+"%@%.2f" = "%@%.2f";
+"%@%@ was spent %@" = "Foram gastos %1$@%2$@ %3$@";
+"%@%lld" = "%@%lld";
+"%@, %@%@, Transaction Category: %@, Transaction made at %@" = "%1$@, %2$@%3$@, categoria da transação: %4$@, transação realizada às %5$@";
+"%lld" = "%lld";
+"%lld%%" = "%lld%%";
+"%lld/^[%lld category](inflect: true) linked" = "%1$lld de %2$lld categorias vinculadas";
+"+%@" = "+%@";
+"-%@" = "-%@";
+"." = ".";
+"0" = "0";
+"ADD\nBUDGET" = "ADICIONAR\nORÇAMENTO";
+"APPEARANCE" = "APARÊNCIA";
+"Add New Transaction" = "Adicionar novo lançamento";
+"Added %@" = "Categoria %@ adicionada";
+"Additional Category Filters" = "Filtros adicionais de categoria";
+"Additional Pointers" = "Orientações adicionais";
+"All dates should be of a consistent, recognizable format. If no timestamps are provided, the time of transaction will default to 12:00 am." = "Todas as datas devem estar em um formato consistente e reconhecível. Se não houver horário, a transação usará 00:00 como padrão.";
+"Amount" = "Valor";
+"An early prototype also designed by @rudra_dsigns that I kinda fancy." = "Um protótipo antigo, também criado por @rudra_dsigns, do qual gosto bastante.";
+"An unknown error occurred: %@" = "Ocorreu um erro desconhecido: %@";
+"App Icon" = "Ícone do app";
+"App Icons" = "Ícones do app";
+"App Locked" = "App bloqueado";
+"App tab" = "Aba do app";
+"Assign amount column" = "Atribua a coluna de valores";
+"Assign category column" = "Atribua a coluna de categorias";
+"Assign date column" = "Atribua a coluna de datas";
+"Assign note column" = "Atribua a coluna de observações";
+"Begin by adding a CSV file with 4 columns: amount, note, date, and category." = "Comece adicionando um arquivo CSV com quatro colunas: valor, observação, data e categoria.";
+"Budget Type" = "Tipo de orçamento";
+"Budget and category creation screens have been completely reworked." = "As telas de criação de orçamentos e categorias foram totalmente reformuladas.";
+"Budget tab" = "Aba Orçamentos";
+"Calculate ${type} for ${timeframe}" = "Calcular ${type} em ${timeframe}";
+"Calculate leftover amount for the ${budget} ${type}" = "Calcular o valor restante de ${type} para ${budget}";
+"Calculate leftover amount for the ${type}" = "Calcular o valor restante de ${type}";
+"Category Budget" = "Orçamento por categoria";
+"Category Filters" = "Filtros de categoria";
+"Category associated with the transaction" = "Categoria associada ao lançamento";
+"Category not found" = "Categoria não encontrada";
+"Change the start of a month's cycle to align with payday." = "Altere o início do ciclo mensal para que coincida com o dia do pagamento.";
+"Check it out in Photos" = "Confira no app Fotos";
+"Choose from 3 new skeuomorphic icons beautifully crafted by the talented @rudra_dsigns." = "Escolha entre três novos ícones esqueumórficos criados pelo talentoso @rudra_dsigns.";
+"Close" = "Fechar";
+"Confirm" = "Confirmar";
+"Couldn't save to CoreData" = "Não foi possível salvar os dados";
+"Custom Category Colors" = "Cores personalizadas de categoria";
+"Custom Time Frames" = "Períodos personalizados";
+"Custom notification time" = "Horário personalizado da notificação";
+"Data Import" = "Importação de dados";
+"Date" = "Data";
+"Date Format" = "Formato da data";
+"Delete %@ transaction confirmation. This action cannot be undone." = "Confirmação para excluir o lançamento %@. Esta ação não pode ser desfeita.";
+"Designed by the brilliant @rudra_dsigns, check out his work on Twitter." = "Criado pelo brilhante @rudra_dsigns. Confira o trabalho dele no Twitter.";
+"Dime definitely isn't becoming one but it never hurts to keep dreaming." = "O Dime definitivamente não está se tornando um unicórnio, mas não custa sonhar.";
+"Display +/- Symbol" = "Exibir símbolo +/−";
+"Display on Log Page" = "Exibir no histórico";
+"Displays transaction suggestions whilst you type in the 'Note' field of the new transaction page." = "Exibe sugestões de lançamentos enquanto você digita no campo de observação da tela de novo lançamento.";
+"Don't worry, even if you do hide them there, you will aways be able to find all upcoming transactions right here." = "Não se preocupe: mesmo que você os oculte, todos os lançamentos futuros continuarão disponíveis aqui.";
+"Duplicate Emoji" = "Emoji duplicado";
+"Duplicate Name" = "Nome duplicado";
+"Emoji" = "Emoji";
+"Ensure that the values in the 'Amount' column do not contain any currency symbols." = "Certifique-se de que os valores da coluna de valor não contenham símbolos de moeda.";
+"Error occurred while matching categories." = "Ocorreu um erro ao associar as categorias.";
+"Excessive" = "Intenso";
+"Expense successfully logged." = "Despesa registrada com sucesso.";
+"Extract leftover amount for a particular budget" = "Consultar o valor restante de um orçamento específico";
+"Extracts your total expenditure or income for a particular time period" = "Consulta o total de despesas ou receitas em um período específico";
+"Feature Request" = "Sugerir recurso";
+"Filter" = "Filtrar";
+"Follow Dime on X" = "Seguir o Dime no X";
+"Follow Rafael on X" = "Seguir o Rafael no X";
+"Frequency" = "Frequência";
+"Future Transactions" = "Lançamentos futuros";
+"Get Budget Insights" = "Consultar orçamento";
+"Get Insights" = "Consultar análises";
+"Haphazardly put together in under 30 minutes, the original Dime icon." = "Montado às pressas em menos de 30 minutos: o ícone original do Dime.";
+"Haptic Feedback" = "Resposta tátil";
+"Haptics" = "Resposta tátil";
+"Here you go!" = "Aqui está!";
+"Hidden" = "Ocultos";
+"How much was transacted?" = "Qual foi o valor do lançamento?";
+"Image Saved" = "Imagem salva";
+"Import" = "Importar";
+"Import Data" = "Importar dados";
+"Import Failed" = "Falha na importação";
+"Import Successful" = "Importação concluída";
+"Import transactions" = "Importe lançamentos";
+"Income successfully logged." = "Receita registrada com sucesso.";
+"Income/Day" = "RECEITA/DIA";
+"Income/Mth" = "RECEITA/MÊS";
+"Indicate budget type" = "Indique o tipo de orçamento";
+"Indicate date format" = "Informe o formato da data";
+"Insights Type" = "Tipo de análise";
+"Insights tab" = "Aba Análises";
+"Insufficient Columns" = "Colunas insuficientes";
+"Invalid Column" = "Coluna inválida";
+"Invalid File" = "Arquivo inválido";
+"Invalid dates in date column." = "Há datas inválidas na coluna de datas.";
+"Invalid values in amount column." = "Há valores inválidos na coluna de valores.";
+"Limit Exceeded" = "Limite excedido";
+"Limit to 14-Day Outlook" = "Limitar aos próximos 14 dias";
+"Link categories" = "Associe as categorias";
+"Log Deleted" = "Lançamento excluído";
+"Log an ${income} of ${amount}" = "Registrar ${income} no valor de ${amount}";
+"Log an ${income} of ${amount} under ${expenseCategory}" = "Registrar ${income} no valor de ${amount} na categoria ${expenseCategory}";
+"Log an ${income} of ${amount} under ${incomeCategory}" = "Registrar ${income} no valor de ${amount} na categoria ${incomeCategory}";
+"Log new transactions in a blink" = "Registre novos lançamentos rapidamente";
+"Log tab" = "Aba Histórico";
+"Match values found in the 'Category' column to the corresponding categories in Dime." = "Associe os valores da coluna de categoria às categorias correspondentes no Dime.";
+"Name" = "Nome";
+"New Toasts" = "Novos alertas";
+"New Transaction" = "Novo lançamento";
+"No categories found" = "Nenhuma categoria encontrada";
+"No category with an ID matching: %@" = "Nenhuma categoria encontrada com o ID: %@";
+"No remaining\ncategories." = "Nenhuma outra\ncategoria.";
+"None" = "Nenhum";
+"Note" = "Observação";
+"Over what time frame would you like to consider?" = "Qual período você deseja considerar?";
+"Please re-enable Face ID access in the Settings app to unlock application." = "Reative o acesso ao Face ID nos Ajustes para desbloquear o app.";
+"Please wait while we process your new transactions." = "Aguarde enquanto processamos seus novos lançamentos.";
+"Press the plus button\nto add your first entry" = "Toque no botão de mais\npara adicionar seu primeiro lançamento";
+"Processing Import" = "Processando importação";
+"Processing import" = "Processe a importação";
+"Pull to add update" = "Puxe para adicionar uma atualização";
+"Quick Add Widget" = "Widget de adição rápida";
+"Re-designed Screens" = "Telas reformuladas";
+"Recurring Frequency" = "Frequência da recorrência";
+"Recurring Transaction" = "Lançamento recorrente";
+"Referencing %@, state the format of the dates in the assigned column." = "Usando %@ como referência, informe o formato das datas na coluna atribuída.";
+"Referencing this article, state the format of the dates in the assigned column." = "Usando este artigo como referência, informe o formato das datas na coluna atribuída.";
+"Remove all commas in the 'Note' and 'Category' columns as they would disrupt the parsing of your file." = "Remova todas as vírgulas das colunas de observação e categoria, pois elas prejudicam a leitura do arquivo.";
+"Sample Sheet" = "Planilha de exemplo";
+"Sample from 'Date' Column" = "Amostra da coluna de data";
+"Sampled Rows from Import CSV" = "Linhas de amostra do CSV";
+"Save as Photo" = "Salvar como foto";
+"Search" = "Buscar";
+"Select a categorical budget." = "Selecione um orçamento por categoria.";
+"Select a column from your import that corresponds to the categories of your transactions." = "Selecione a coluna do arquivo que corresponde às categorias dos lançamentos.";
+"Select a column from your import that corresponds to the dates of your transactions." = "Selecione a coluna do arquivo que corresponde às datas dos lançamentos.";
+"Select a column from your import that corresponds to the notes/subtitles of your transactions." = "Selecione a coluna do arquivo que corresponde às observações dos lançamentos.";
+"Select a column from your import that corresponds to the values of your transactions." = "Selecione a coluna do arquivo que corresponde aos valores dos lançamentos.";
+"Settings tab" = "Aba Ajustes";
+"Show Note Suggestions" = "Exibir sugestões de observação";
+"Shown" = "Exibidos";
+"Similarly, alert toasts across the app have been re-designed." = "Os alertas exibidos pelo app também foram reformulados.";
+"Siri Shortcuts" = "Atalhos da Siri";
+"Special thanks to %@ for contributing" = "Agradecimento especial a %@ pela contribuição";
+"Spent/Day" = "GASTO/DIA";
+"Spent/Mth" = "GASTO/MÊS";
+"Start" = "Início";
+"Start of Month" = "Início do mês";
+"Stop Recurring" = "Interromper recorrência";
+"Stop Recurring?" = "Interromper recorrência?";
+"Subtle" = "Sutil";
+"Tap to Undo" = "Toque para desfazer";
+"Thanks a million, ❤️ Rafael" = "Muito obrigado, ❤️ Rafael";
+"The 'Excessive' mode makes the entire numpad haptic." = "O modo intenso ativa a resposta tátil em todo o teclado numérico.";
+"The overall budget tracks expenses across the board, while categorical budgets are tied to expenses of a particular type only." = "O orçamento geral acompanha todas as despesas, enquanto os orçamentos por categoria se aplicam somente a despesas de um tipo específico.";
+"The transaction will no longer be automatically logged." = "O lançamento não será mais registrado automaticamente.";
+"Theme" = "Tema";
+"Time Frame" = "Período";
+"Time Frame of Data" = "Período dos dados";
+"Time Frames" = "Períodos";
+"Transfer pre-existing logs from other applications with a step-by-step guide." = "Transfira lançamentos de outros aplicativos com um guia passo a passo.";
+"Try your best to stay under this limit! Also, feel free to change this in the future." = "Tente permanecer abaixo desse limite. Você poderá alterá-lo depois.";
+"Type" = "Tipo";
+"Type of Data" = "Tipo de dado";
+"Type of the transaction" = "Tipo do lançamento";
+"UPCOMING" = "PRÓXIMOS";
+"Unlinked Categories" = "Categorias não associadas";
+"Unknown" = "Desconhecida";
+"Unlock App" = "Desbloquear app";
+"Upcoming Logs" = "Lançamentos futuros";
+"Using the stock iOS color picker, give your categories a long-awaited aesthetic refresh." = "Use o seletor de cores do iOS para personalizar a aparência das suas categorias.";
+"Value of the transaction" = "Valor do lançamento";
+"Version %@ (%@) · 18 Sep 2023" = "Versão %@ (%@) · 18 de set. de 2023";
+"What budget type would you like to extract insights from?" = "Que tipo de orçamento você deseja consultar?";
+"What category does it come under?" = "A qual categoria pertence?";
+"What's New" = "Novidades";
+"What's New?" = "Novidades";
+"Which additional category filters do you want to impose?" = "Quais filtros adicionais de categoria você deseja aplicar?";
+"Which of the following would you like to extract?" = "Qual das opções você deseja consultar?";
+"With date restrictions lifted, log and view upcoming expenses/incomes." = "Com as restrições de data removidas, registre e visualize receitas e despesas futuras.";
+"Would you like to log an income or expense?" = "Você deseja registrar uma receita ou uma despesa?";
+"all time" = "todo o período";
+"button to make transaction recurring" = "botão para tornar o lançamento recorrente";
+"categorical budget" = "orçamento por categoria";
+"day" = "dia";
+"delete transaction" = "excluir lançamento";
+"expense" = "despesa";
+"hello world" = "olá, mundo";
+"income" = "receita";
+"net total" = "saldo total";
+"next day" = "próximo dia";
+"next month" = "próximo mês";
+"next week" = "próxima semana";
+"on %@" = "em %@";
+"previous day" = "dia anterior";
+"previous month" = "mês anterior";
+"previous week" = "semana anterior";
+"remove filter" = "remover filtro";
+"showing transactions from %@ to %@" = "exibindo lançamentos de %@ a %@";
+"showing transactions in %@" = "exibindo lançamentos em %@";
+"showing transactions on %@" = "exibindo lançamentos em %@";
+"total expenditure" = "total de despesas";
+"total income" = "receita total";
+"transaction recurs daily, button to edit recurring duration" = "lançamento recorrente diário; botão para editar a duração";
+"transaction recurs monthly, button to edit recurring duration" = "lançamento recorrente mensal; botão para editar a duração";
+"transaction recurs weekly, button to edit recurring duration" = "lançamento recorrente semanal; botão para editar a duração";
+"Support Email" = "Suporte do Dime";
+"3 new Siri shortcuts allow you to conveniently add new transactions or access insights." = "Três novos atalhos da Siri permitem adicionar lançamentos ou consultar análises com praticidade.";
+"%@%@" = "%@%@";
+"%@0 %@ %@" = "%@0 %@ %@";
+"~%@ /day" = "~%@ /dia";
+"·" = "·";
+"•" = "•";
+"📭️" = "📭️";
+"🙈" = "🙈";
diff --git a/app/Localizations/pt-BR.lproj/Localizable.stringsdict b/app/Localizations/pt-BR.lproj/Localizable.stringsdict
new file mode 100644
index 0000000..6fc1087
--- /dev/null
+++ b/app/Localizations/pt-BR.lproj/Localizable.stringsdict
@@ -0,0 +1,150 @@
+
+
+
+
+ %lld days left
+
+ NSStringLocalizedFormatKey
+ %#@VARIABLE@
+ VARIABLE
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ lld
+ zero
+ Vazio
+ one
+ 1 dia restante
+ other
+ %lld dias restantes
+
+
+ %lld hours left
+
+ NSStringLocalizedFormatKey
+ %#@VARIABLE@
+ VARIABLE
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ lld
+ zero
+ Vazio
+ one
+ 1 hora restante
+ other
+ %lld horas restantes
+
+
+ %lld days
+
+ NSStringLocalizedFormatKey
+ %#@VARIABLE@
+ VARIABLE
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ lld
+ zero
+ 0 dias
+ one
+ 1 dia
+ other
+ %lld dias
+
+
+ %lld weeks
+
+ NSStringLocalizedFormatKey
+ %#@VARIABLE@
+ VARIABLE
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ lld
+ zero
+ 0 semanas
+ one
+ 1 semana
+ other
+ %lld semanas
+
+
+ %lld months
+
+ NSStringLocalizedFormatKey
+ %#@VARIABLE@
+ VARIABLE
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ lld
+ zero
+ 0 meses
+ one
+ 1 mês
+ other
+ %lld meses
+
+
+ %lld weeks ago
+
+ NSStringLocalizedFormatKey
+ %#@VARIABLE@
+ VARIABLE
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ lld
+ zero
+ 0 semanas atrás
+ one
+ 1 semana atrás
+ other
+ %lld semanas atrás
+
+
+ %lld months ago
+
+ NSStringLocalizedFormatKey
+ %#@VARIABLE@
+ VARIABLE
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ lld
+ zero
+ 0 meses atrás
+ one
+ 1 mês atrás
+ other
+ %lld meses atrás
+
+
+ %lld years ago
+
+ NSStringLocalizedFormatKey
+ %#@VARIABLE@
+ VARIABLE
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ lld
+ zero
+ 0 anos atrás
+ one
+ 1 ano atrás
+ other
+ %lld anos atrás
+
+
+
+
diff --git a/app/dime.xcodeproj/project.pbxproj b/app/dime.xcodeproj/project.pbxproj
index 4598761..b2457cd 100644
--- a/app/dime.xcodeproj/project.pbxproj
+++ b/app/dime.xcodeproj/project.pbxproj
@@ -156,6 +156,17 @@
AECE7F9E2AED1A6800B57267 /* SuggestedTransactions.swift in Sources */ = {isa = PBXBuildFile; fileRef = AECE7F9D2AED1A6800B57267 /* SuggestedTransactions.swift */; };
D63B204A2D8728C300CAFB20 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D63B20462D8728C300CAFB20 /* Localizable.strings */; };
D63B204B2D8728C300CAFB20 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = D63B20482D8728C300CAFB20 /* Localizable.stringsdict */; };
+ D63B20562D8728C300CAFB20 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D63B20462D8728C300CAFB20 /* Localizable.strings */; };
+ D63B20572D8728C300CAFB20 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = D63B20482D8728C300CAFB20 /* Localizable.stringsdict */; };
+ D63B20582D8728C300CAFB20 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = D63B20482D8728C300CAFB20 /* Localizable.stringsdict */; };
+ D63B20592D8728C300CAFB20 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = D63B20482D8728C300CAFB20 /* Localizable.stringsdict */; };
+ D63B20602D8728C300CAFB20 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D63B20462D8728C300CAFB20 /* Localizable.strings */; };
+ D63B20612D8728C300CAFB20 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D63B20462D8728C300CAFB20 /* Localizable.strings */; };
+ D63B20622D8728C300CAFB20 /* AppShortcuts.strings in Resources */ = {isa = PBXBuildFile; fileRef = D63B20682D8728C300CAFB20 /* AppShortcuts.strings */; };
+ D63B20632D8728C300CAFB20 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D63B20692D8728C300CAFB20 /* InfoPlist.strings */; };
+ D63B20702D8728C300CAFB20 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D63B20792D8728C300CAFB20 /* InfoPlist.strings */; };
+ D63B20712D8728C300CAFB20 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D63B207A2D8728C300CAFB20 /* InfoPlist.strings */; };
+ D63B20722D8728C300CAFB20 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D63B207B2D8728C300CAFB20 /* InfoPlist.strings */; };
D6A4DE202D61744400F7F751 /* SwiftUIIntrospect in Frameworks */ = {isa = PBXBuildFile; productRef = D6A4DE1F2D61744400F7F751 /* SwiftUIIntrospect */; };
D6A4DE242D61744400F7F751 /* SwiftUIIntrospect-Static in Frameworks */ = {isa = PBXBuildFile; productRef = D6A4DE232D61744400F7F751 /* SwiftUIIntrospect-Static */; };
/* End PBXBuildFile section */
@@ -214,6 +225,10 @@
530C89D52A793B6C00B5028D /* ShortcutsEntities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutsEntities.swift; sourceTree = ""; };
530C9DFC28ACE14A0038535F /* BudgetWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BudgetWidget.swift; sourceTree = ""; };
5311A22E29F04EF300A5BE20 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; name = Base; path = Base.lproj/WidgetConfiguration.intentdefinition; sourceTree = ""; };
+ D63B20522D8728C300CAFB20 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/WidgetConfiguration.strings; sourceTree = ""; };
+ D63B20532D8728C300CAFB20 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/WidgetConfiguration.strings; sourceTree = ""; };
+ D63B20542D8728C300CAFB20 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/WidgetConfiguration.strings; sourceTree = ""; };
+ D63B20552D8728C300CAFB20 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/WidgetConfiguration.strings"; sourceTree = ""; };
5313EC5B28ACE941000EAB0C /* BudgetIntent.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = BudgetIntent.appex; sourceTree = BUILT_PRODUCTS_DIR; };
5313EC5C28ACE941000EAB0C /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; };
5313EC5F28ACE941000EAB0C /* IntentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentHandler.swift; sourceTree = ""; };
@@ -333,6 +348,22 @@
AECE7F9D2AED1A6800B57267 /* SuggestedTransactions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestedTransactions.swift; sourceTree = ""; };
D63B20472D8728C300CAFB20 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = Localizations/en.lproj/Localizable.strings; sourceTree = ""; };
D63B20492D8728C300CAFB20 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = Localizations/en.lproj/Localizable.stringsdict; sourceTree = ""; };
+ D63B204C2D8728C300CAFB20 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = Localizations/fr.lproj/Localizable.strings; sourceTree = ""; };
+ D63B204D2D8728C300CAFB20 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = fr; path = Localizations/fr.lproj/Localizable.stringsdict; sourceTree = ""; };
+ D63B204E2D8728C300CAFB20 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = Localizations/ru.lproj/Localizable.strings; sourceTree = ""; };
+ D63B204F2D8728C300CAFB20 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ru; path = Localizations/ru.lproj/Localizable.stringsdict; sourceTree = ""; };
+ D63B20502D8728C300CAFB20 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "Localizations/pt-BR.lproj/Localizable.strings"; sourceTree = ""; };
+ D63B20512D8728C300CAFB20 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "pt-BR"; path = "Localizations/pt-BR.lproj/Localizable.stringsdict"; sourceTree = ""; };
+ D63B20642D8728C300CAFB20 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = Localizations/en.lproj/AppShortcuts.strings; sourceTree = ""; };
+ D63B20652D8728C300CAFB20 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "Localizations/pt-BR.lproj/AppShortcuts.strings"; sourceTree = ""; };
+ D63B20662D8728C300CAFB20 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = Localizations/en.lproj/InfoPlist.strings; sourceTree = ""; };
+ D63B20672D8728C300CAFB20 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "Localizations/pt-BR.lproj/InfoPlist.strings"; sourceTree = ""; };
+ D63B20732D8728C300CAFB20 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
+ D63B20742D8728C300CAFB20 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/InfoPlist.strings"; sourceTree = ""; };
+ D63B20752D8728C300CAFB20 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
+ D63B20762D8728C300CAFB20 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/InfoPlist.strings"; sourceTree = ""; };
+ D63B20772D8728C300CAFB20 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
+ D63B20782D8728C300CAFB20 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/InfoPlist.strings"; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -394,6 +425,7 @@
5313EC5E28ACE941000EAB0C /* BudgetIntent */ = {
isa = PBXGroup;
children = (
+ D63B20792D8728C300CAFB20 /* InfoPlist.strings */,
537152DD28AD0E6B00E93EC4 /* BudgetIntent.entitlements */,
5313EC5F28ACE941000EAB0C /* IntentHandler.swift */,
5313EC6128ACE941000EAB0C /* Info.plist */,
@@ -404,6 +436,7 @@
5313EC6928ACE941000EAB0C /* BudgetIntentUI */ = {
isa = PBXGroup;
children = (
+ D63B207A2D8728C300CAFB20 /* InfoPlist.strings */,
537152DE28AD0E7900E93EC4 /* BudgetIntentUI.entitlements */,
5313EC6A28ACE941000EAB0C /* IntentViewController.swift */,
5313EC6C28ACE941000EAB0C /* MainInterface.storyboard */,
@@ -417,6 +450,8 @@
children = (
D63B20462D8728C300CAFB20 /* Localizable.strings */,
D63B20482D8728C300CAFB20 /* Localizable.stringsdict */,
+ D63B20682D8728C300CAFB20 /* AppShortcuts.strings */,
+ D63B20692D8728C300CAFB20 /* InfoPlist.strings */,
53EB931028A65F670026BE28 /* ExpenditureWidgetExtension.entitlements */,
5327D285287C697400F76ADF /* dime */,
53B1D18F288ED7E500E28062 /* ExpenditureWidget */,
@@ -570,6 +605,7 @@
53B1D18F288ED7E500E28062 /* ExpenditureWidget */ = {
isa = PBXGroup;
children = (
+ D63B207B2D8728C300CAFB20 /* InfoPlist.strings */,
53B1D190288ED7E500E28062 /* ExpenditureWidget.swift */,
5324985428A64DA7007B34D1 /* RecentTransactionsWidget.swift */,
53D5F02228A8E0E4004573C8 /* InsightsWidget.swift */,
@@ -785,6 +821,9 @@
hasScannedForEncodings = 0;
knownRegions = (
en,
+ fr,
+ ru,
+ "pt-BR",
Base,
);
mainGroup = 5327D27A287C697400F76ADF;
@@ -814,6 +853,9 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ D63B20702D8728C300CAFB20 /* InfoPlist.strings in Resources */,
+ D63B20602D8728C300CAFB20 /* Localizable.strings in Resources */,
+ D63B20582D8728C300CAFB20 /* Localizable.stringsdict in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -822,6 +864,9 @@
buildActionMask = 2147483647;
files = (
5313EC6E28ACE941000EAB0C /* MainInterface.storyboard in Resources */,
+ D63B20712D8728C300CAFB20 /* InfoPlist.strings in Resources */,
+ D63B20612D8728C300CAFB20 /* Localizable.strings in Resources */,
+ D63B20592D8728C300CAFB20 /* Localizable.stringsdict in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -830,6 +875,8 @@
buildActionMask = 2147483647;
files = (
5327D28E287C697C00F76ADF /* Preview Assets.xcassets in Resources */,
+ D63B20622D8728C300CAFB20 /* AppShortcuts.strings in Resources */,
+ D63B20632D8728C300CAFB20 /* InfoPlist.strings in Resources */,
D63B204A2D8728C300CAFB20 /* Localizable.strings in Resources */,
D63B204B2D8728C300CAFB20 /* Localizable.stringsdict in Resources */,
5327D295287C698900F76ADF /* Assets.xcassets in Resources */,
@@ -843,6 +890,9 @@
buildActionMask = 2147483647;
files = (
533182D328A0D61D00DEBFA3 /* Assets.xcassets in Resources */,
+ D63B20722D8728C300CAFB20 /* InfoPlist.strings in Resources */,
+ D63B20562D8728C300CAFB20 /* Localizable.strings in Resources */,
+ D63B20572D8728C300CAFB20 /* Localizable.stringsdict in Resources */,
53B1D193288ED87000E28062 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -1049,6 +1099,10 @@
isa = PBXVariantGroup;
children = (
5311A22E29F04EF300A5BE20 /* Base */,
+ D63B20522D8728C300CAFB20 /* en */,
+ D63B20532D8728C300CAFB20 /* fr */,
+ D63B20542D8728C300CAFB20 /* ru */,
+ D63B20552D8728C300CAFB20 /* pt-BR */,
);
name = WidgetConfiguration.intentdefinition;
sourceTree = "";
@@ -1065,6 +1119,9 @@
isa = PBXVariantGroup;
children = (
D63B20472D8728C300CAFB20 /* en */,
+ D63B204C2D8728C300CAFB20 /* fr */,
+ D63B204E2D8728C300CAFB20 /* ru */,
+ D63B20502D8728C300CAFB20 /* pt-BR */,
);
name = Localizable.strings;
sourceTree = "";
@@ -1073,10 +1130,58 @@
isa = PBXVariantGroup;
children = (
D63B20492D8728C300CAFB20 /* en */,
+ D63B204D2D8728C300CAFB20 /* fr */,
+ D63B204F2D8728C300CAFB20 /* ru */,
+ D63B20512D8728C300CAFB20 /* pt-BR */,
);
name = Localizable.stringsdict;
sourceTree = "";
};
+ D63B20682D8728C300CAFB20 /* AppShortcuts.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ D63B20642D8728C300CAFB20 /* en */,
+ D63B20652D8728C300CAFB20 /* pt-BR */,
+ );
+ name = AppShortcuts.strings;
+ sourceTree = "";
+ };
+ D63B20692D8728C300CAFB20 /* InfoPlist.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ D63B20662D8728C300CAFB20 /* en */,
+ D63B20672D8728C300CAFB20 /* pt-BR */,
+ );
+ name = InfoPlist.strings;
+ sourceTree = "";
+ };
+ D63B20792D8728C300CAFB20 /* InfoPlist.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ D63B20732D8728C300CAFB20 /* en */,
+ D63B20742D8728C300CAFB20 /* pt-BR */,
+ );
+ name = InfoPlist.strings;
+ sourceTree = "";
+ };
+ D63B207A2D8728C300CAFB20 /* InfoPlist.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ D63B20752D8728C300CAFB20 /* en */,
+ D63B20762D8728C300CAFB20 /* pt-BR */,
+ );
+ name = InfoPlist.strings;
+ sourceTree = "";
+ };
+ D63B207B2D8728C300CAFB20 /* InfoPlist.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ D63B20772D8728C300CAFB20 /* en */,
+ D63B20782D8728C300CAFB20 /* pt-BR */,
+ );
+ name = InfoPlist.strings;
+ sourceTree = "";
+ };
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
diff --git a/app/dime.xcodeproj/xcshareddata/xcschemes/dime.xcscheme b/app/dime.xcodeproj/xcshareddata/xcschemes/dime.xcscheme
index 109d5ee..077a042 100644
--- a/app/dime.xcodeproj/xcshareddata/xcschemes/dime.xcscheme
+++ b/app/dime.xcodeproj/xcshareddata/xcschemes/dime.xcscheme
@@ -34,7 +34,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- language = "en"
region = "SG"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
diff --git a/app/dime/Components/Buttons/AlertButtons.swift b/app/dime/Components/Buttons/AlertButtons.swift
index 33dd284..b21388f 100644
--- a/app/dime/Components/Buttons/AlertButtons.swift
+++ b/app/dime/Components/Buttons/AlertButtons.swift
@@ -9,7 +9,7 @@ import Foundation
import SwiftUI
struct DeleteButton: View {
- let text: String
+ let text: LocalizedStringKey
let red: Bool
var body: some View {
diff --git a/app/dime/Shortcuts/Actions/BudgetInsightsIntent.swift b/app/dime/Shortcuts/Actions/BudgetInsightsIntent.swift
index e60c289..b161f2d 100644
--- a/app/dime/Shortcuts/Actions/BudgetInsightsIntent.swift
+++ b/app/dime/Shortcuts/Actions/BudgetInsightsIntent.swift
@@ -107,7 +107,7 @@ struct ShortcutBudgetView: View {
case 4:
return String(localized: "this year")
default:
- return "this week"
+ return String(localized: "this week")
}
}
diff --git a/app/dime/Shortcuts/Actions/GetInsightsIntent.swift b/app/dime/Shortcuts/Actions/GetInsightsIntent.swift
index a8913bf..15b036d 100644
--- a/app/dime/Shortcuts/Actions/GetInsightsIntent.swift
+++ b/app/dime/Shortcuts/Actions/GetInsightsIntent.swift
@@ -146,26 +146,26 @@ struct ShortcutInsightsView: View {
var leftText: String {
switch type {
case .net:
- return "Net total"
+ return String(localized: "Net total")
case .income:
- return "Earned"
+ return String(localized: "Earned")
case .spent:
- return "Spent"
+ return String(localized: "Spent")
}
}
var rightText: String {
switch timeframe {
case .day:
- return "today"
+ return String(localized: "today")
case .week:
- return "this week"
+ return String(localized: "this week")
case .month:
- return "this month"
+ return String(localized: "this month")
case .year:
- return "this year"
+ return String(localized: "this year")
case .all:
- return "all time"
+ return String(localized: "all time")
}
}
diff --git a/app/dime/Views/BudgetView.swift b/app/dime/Views/BudgetView.swift
index d79a43f..6608bfa 100644
--- a/app/dime/Views/BudgetView.swift
+++ b/app/dime/Views/BudgetView.swift
@@ -281,7 +281,7 @@ struct MainBudgetView: View {
case 4:
return String(localized: "this year")
default:
- return "this week"
+ return String(localized: "this week")
}
}
@@ -421,7 +421,7 @@ struct MainBudgetView: View {
BudgetDollarView(amount: difference, red: totalSpent >= budgetAmount, scale: 3, size: internalWidth)
.frame(width: internalWidth)
- Text("\(budgetAmount >= totalSpent ? "left" : "over") \(budgetType)")
+ Text("\(budgetAmount >= totalSpent ? String(localized: "left") : String(localized: "over")) \(budgetType)")
.font(.system(.subheadline, design: .rounded).weight(.medium))
// .font(.system(size: 15, weight: .medium, design: .rounded))
.foregroundColor(Color.SubtitleText)
@@ -546,7 +546,7 @@ struct SingleBudgetView: View {
case 4:
return String(localized: "this year")
default:
- return "this week"
+ return String(localized: "this week")
}
}
@@ -710,7 +710,7 @@ struct SingleBudgetView: View {
VStack(alignment: .trailing, spacing: -4) {
BudgetDollarView(amount: difference, red: totalSpent >= budgetAmount, scale: 1, size: 80)
- Text("\(budgetAmount >= totalSpent ? "left" : "over") \(budgetType)")
+ Text("\(budgetAmount >= totalSpent ? String(localized: "left") : String(localized: "over")) \(budgetType)")
.font(.system(.caption2, design: .rounded).weight(.medium))
.foregroundColor(Color.SubtitleText)
}
@@ -830,7 +830,7 @@ struct SingleBudgetView: View {
BudgetDollarView(amount: difference, red: totalSpent >= budgetAmount, scale: 2, size: width - 40)
- Text("\(budgetAmount >= totalSpent ? "left" : "over") \(budgetType)")
+ Text("\(budgetAmount >= totalSpent ? String(localized: "left") : String(localized: "over")) \(budgetType)")
.font(.system(.footnote, design: .rounded).weight(.medium))
.foregroundColor(Color.SubtitleText)
.minimumScaleFactor(0.7)
diff --git a/app/dime/Views/CategoryView.swift b/app/dime/Views/CategoryView.swift
index f2a0011..37a3580 100644
--- a/app/dime/Views/CategoryView.swift
+++ b/app/dime/Views/CategoryView.swift
@@ -114,7 +114,7 @@ struct CategoryView: View {
if disabled {
showToast = true
toastImage = "exclamationmark.triangle.fill"
- toastTitle = "Limit Exceeded"
+ toastTitle = String(localized: "Limit Exceeded")
positive = false
} else {
newCategory = true
@@ -492,7 +492,7 @@ struct CategoryListView: View {
.environment(\.editMode, .constant(self.isEditing ? EditMode.active : EditMode.inactive))
} else {
List {
- Section(header: Text("\(income ? "INCOME" : "EXPENSE") CATEGORIES").foregroundColor(Color.SubtitleText)) {
+ Section(header: Text(income ? LocalizedStringKey("INCOME CATEGORIES") : LocalizedStringKey("EXPENSE CATEGORIES")).foregroundColor(Color.SubtitleText)) {
if categories.isEmpty {
VStack(spacing: 10) {
Image(systemName: "tray")
@@ -501,7 +501,7 @@ struct CategoryListView: View {
// .font(.system(size: 37, weight: .light))
.foregroundColor(Color.SubtitleText)
- Text("No \(income ? "income" : "expense") categories found,\nclick the 'New' button to add some.")
+ Text(income ? LocalizedStringKey("no_income_categories") : LocalizedStringKey("no_expense_categories"))
.font(.system(.body, design: .rounded).weight(.medium))
.dynamicTypeSize(...DynamicTypeSize.xxxLarge)
// .font(.system(size: 17, weight: .medium, design: .rounded))
@@ -688,7 +688,7 @@ struct CategoryListView: View {
}
.onChange(of: showSuggestions) { newValue in
if !newValue {
- toastTitle = "Suggestions Hidden"
+ toastTitle = String(localized: "Suggestions Hidden")
toastImage = "eye.slash"
showToast = true
positive = true
@@ -985,7 +985,7 @@ struct NewCategoryAlert: View {
// }
// }
// }
- NormalTextField(text: $newName, placeholder: "Category Name", action: verification)
+ NormalTextField(text: $newName, placeholder: String(localized: "Category Name"), action: verification)
.focused($focusedField, equals: .name)
.padding(.horizontal, 15)
.padding(.vertical, 5)
@@ -1065,28 +1065,28 @@ struct NewCategoryAlert: View {
switch outcome {
case .incomplete:
- toastTitle = "Incomplete Entry"
+ toastTitle = String(localized: "Incomplete Entry")
toastImage = "questionmark.app"
case .missingEmoji:
- toastTitle = "Missing Emoji"
+ toastTitle = String(localized: "Missing Emoji")
toastImage = "person.fill"
focusedField = .emoji
case .missingName:
- toastTitle = "Missing Name"
+ toastTitle = String(localized: "Missing Name")
toastImage = "character.cursor.ibeam"
focusedField = .name
case .duplicate:
- toastTitle = "Duplicate Found"
+ toastTitle = String(localized: "Duplicate Found")
toastImage = "externaldrive"
case .duplicateEmoji:
- toastTitle = "Duplicate Emoji"
+ toastTitle = String(localized: "Duplicate Emoji")
toastImage = "person.fill"
focusedField = .emoji
case .duplicateName:
- toastTitle = "Duplicate Name"
+ toastTitle = String(localized: "Duplicate Name")
toastImage = "character.cursor.ibeam"
focusedField = .name
@@ -1098,7 +1098,7 @@ struct NewCategoryAlert: View {
showToast = true
} else {
- toastTitle = "Added \(newName)"
+ toastTitle = String(localized: "Added \(newName)")
let generator = UINotificationFeedbackGenerator()
generator.notificationOccurred(.success)
@@ -1386,7 +1386,7 @@ struct EditCategoryAlert: View {
}
}
- NormalTextField(text: $newName, placeholder: "Category Name", action: verification)
+ NormalTextField(text: $newName, placeholder: String(localized: "Category Name"), action: verification)
.focused($focusedField, equals: .name)
.padding(.horizontal, 15)
.padding(.vertical, 5)
@@ -1460,28 +1460,28 @@ struct EditCategoryAlert: View {
switch outcome {
case .incomplete:
- toastTitle = "Incomplete Entry"
+ toastTitle = String(localized: "Incomplete Entry")
toastImage = "questionmark.app"
case .missingEmoji:
- toastTitle = "Missing Emoji"
+ toastTitle = String(localized: "Missing Emoji")
toastImage = "person.fill"
focusedField = .emoji
case .missingName:
- toastTitle = "Missing Name"
+ toastTitle = String(localized: "Missing Name")
toastImage = "character.cursor.ibeam"
focusedField = .name
case .duplicate:
- toastTitle = "Duplicate Found"
+ toastTitle = String(localized: "Duplicate Found")
toastImage = "externaldrive"
case .duplicateEmoji:
- toastTitle = "Duplicate Emoji"
+ toastTitle = String(localized: "Duplicate Emoji")
toastImage = "person.fill"
focusedField = .emoji
case .duplicateName:
- toastTitle = "Duplicate Name"
+ toastTitle = String(localized: "Duplicate Name")
toastImage = "character.cursor.ibeam"
focusedField = .name
diff --git a/app/dime/Views/CustomTabBar.swift b/app/dime/Views/CustomTabBar.swift
index d1724cb..34cd57c 100644
--- a/app/dime/Views/CustomTabBar.swift
+++ b/app/dime/Views/CustomTabBar.swift
@@ -148,6 +148,21 @@ struct TabButton: View {
var zoomed: Bool
@Binding var currentTab: String
+ var localizedAccessibilityLabel: String {
+ switch image {
+ case "Log":
+ return String(localized: "Log tab")
+ case "Insights":
+ return String(localized: "Insights tab")
+ case "Budget":
+ return String(localized: "Budget tab")
+ case "Settings":
+ return String(localized: "Settings tab")
+ default:
+ return String(localized: "App tab")
+ }
+ }
+
var body: some View {
Button {
DispatchQueue.main.async {
@@ -163,7 +178,7 @@ struct TabButton: View {
.foregroundColor(currentTab == image ? Color.DarkIcon : Color.GreyIcon)
}
.buttonStyle(BouncyButton(duration: 0.3, scale: 0.6))
- .accessibilityLabel("\(image) tab")
+ .accessibilityLabel(localizedAccessibilityLabel)
.accessibilityAddTraits(
currentTab == image
? [.isButton, .isSelected]
diff --git a/app/dime/Views/HomeView.swift b/app/dime/Views/HomeView.swift
index 4962984..dbfeeeb 100644
--- a/app/dime/Views/HomeView.swift
+++ b/app/dime/Views/HomeView.swift
@@ -119,10 +119,10 @@ struct HomeView: View {
}
}
.toast(isPresenting: $toastPresenter.showToast, duration: 4, tapToDismiss: true, offsetY: 12, alert: {
- AlertToast(displayMode: .hud, type: .systemImage("checkmark.circle.fill", Color.IncomeGreen), title: "Image Saved", subTitle: "Check it out in Photos")
+ AlertToast(displayMode: .hud, type: .systemImage("checkmark.circle.fill", Color.IncomeGreen), title: String(localized: "Image Saved"), subTitle: String(localized: "Check it out in Photos"))
})
.toast(isPresenting: $transactionManager.showToast, duration: 4, tapToDismiss: true, offsetY: 12, alert: {
- AlertToast(displayMode: .hud, type: .systemImage("arrow.uturn.backward.circle.fill", Color.AlertRed), title: "Log Deleted", subTitle: "Tap to Undo")
+ AlertToast(displayMode: .hud, type: .systemImage("arrow.uturn.backward.circle.fill", Color.AlertRed), title: String(localized: "Log Deleted"), subTitle: String(localized: "Tap to Undo"))
}, onTap: {
withAnimation(.easeInOut(duration: 0.5)) {
moc.rollback()
diff --git a/app/dime/Views/ImportDataView.swift b/app/dime/Views/ImportDataView.swift
index ea1b775..496e8d6 100644
--- a/app/dime/Views/ImportDataView.swift
+++ b/app/dime/Views/ImportDataView.swift
@@ -13,7 +13,8 @@ import UniformTypeIdentifiers
struct ColumnLabel {
let image: String
- let label: String
+ let color: String
+ let label: LocalizedStringKey
}
enum ProcessingState {
@@ -81,7 +82,7 @@ struct ImportDataView: View {
@State var uniqueCategories: [MatchedCategory] = .init()
@State var processingState = ProcessingState.loading
- @State var errorMessage = "Invalid dates in date column."
+ @State var errorMessage = String(localized: "Invalid dates in date column.")
@State var confettiNumber = 0
var numberOfLinkedCategories: Int {
@@ -89,7 +90,7 @@ struct ImportDataView: View {
}
@State var showToast = false
- @State var toastMessage: String = "Invalid File"
+ @State var toastMessage: String = String(localized: "Invalid File")
@State var showingCategoryView = false
@State var pageIndex = 0
@@ -108,24 +109,28 @@ struct ImportDataView: View {
}
let instructions: [InstructionHeadings] = [
- InstructionHeadings(title: "Import transactions", subtitle: "Begin by adding a CSV file with 4 columns: amount, note, date, and category."),
- InstructionHeadings(title: "Assign category column", subtitle: "Select a column from your import that corresponds to the categories of your transactions."),
- InstructionHeadings(title: "Assign note column", subtitle: "Select a column from your import that corresponds to the notes/subtitles of your transactions."),
- InstructionHeadings(title: "Assign date column", subtitle: "Select a column from your import that corresponds to the dates of your transactions."),
- InstructionHeadings(title: "Assign amount column", subtitle: "Select a column from your import that corresponds to the values of your transactions."),
- InstructionHeadings(title: "Indicate date format", subtitle: "Referencing this article, state the format of the dates in the assigned column."),
- InstructionHeadings(title: "Link categories", subtitle: "Match values found in the 'Category' column to the corresponding categories in Dime."),
- InstructionHeadings(title: "Processing import", subtitle: "Please wait while we process your new transactions.")
+ InstructionHeadings(title: String(localized: "Import transactions"), subtitle: String(localized: "Begin by adding a CSV file with 4 columns: amount, note, date, and category.")),
+ InstructionHeadings(title: String(localized: "Assign category column"), subtitle: String(localized: "Select a column from your import that corresponds to the categories of your transactions.")),
+ InstructionHeadings(title: String(localized: "Assign note column"), subtitle: String(localized: "Select a column from your import that corresponds to the notes/subtitles of your transactions.")),
+ InstructionHeadings(title: String(localized: "Assign date column"), subtitle: String(localized: "Select a column from your import that corresponds to the dates of your transactions.")),
+ InstructionHeadings(title: String(localized: "Assign amount column"), subtitle: String(localized: "Select a column from your import that corresponds to the values of your transactions.")),
+ InstructionHeadings(title: String(localized: "Indicate date format"), subtitle: String(localized: "Referencing this article, state the format of the dates in the assigned column.")),
+ InstructionHeadings(title: String(localized: "Link categories"), subtitle: String(localized: "Match values found in the 'Category' column to the corresponding categories in Dime.")),
+ InstructionHeadings(title: String(localized: "Processing import"), subtitle: String(localized: "Please wait while we process your new transactions."))
]
let labels: [ColumnLabel] = [
- ColumnLabel(image: "square.grid.2x2.fill", label: "Category"),
- ColumnLabel(image: "doc.plaintext.fill", label: "Note"),
- ColumnLabel(image: "calendar", label: "Date"),
- ColumnLabel(image: "dollarsign.circle.fill", label: "Amount")
+ ColumnLabel(image: "square.grid.2x2.fill", color: "Category", label: "Category"),
+ ColumnLabel(image: "doc.plaintext.fill", color: "Note", label: "Note"),
+ ColumnLabel(image: "calendar", color: "Date", label: "Date"),
+ ColumnLabel(image: "dollarsign.circle.fill", color: "Amount", label: "Amount")
]
- let pointers = ["Ensure that the values in the 'Amount' column do not contain any currency symbols.", "All dates should be of a consistent, recognizable format. If no timestamps are provided, the time of transaction will default to 12:00 am.", "Remove all commas in the 'Note' and 'Category' columns as they would disrupt the parsing of your file."]
+ let pointers = [
+ String(localized: "Ensure that the values in the 'Amount' column do not contain any currency symbols."),
+ String(localized: "All dates should be of a consistent, recognizable format. If no timestamps are provided, the time of transaction will default to 12:00 am."),
+ String(localized: "Remove all commas in the 'Note' and 'Category' columns as they would disrupt the parsing of your file.")
+ ]
var incomeCategories: [Category] {
dataController.getAllCategories(income: true)
@@ -401,8 +406,8 @@ struct ImportDataView: View {
}
.padding(.horizontal, 10)
.frame(width: columnWidth, height: 30, alignment: .leading)
- .foregroundColor(Color(labels[index].label))
- .background(Color(labels[index].label).opacity(0.23), in: RoundedCorner(radius: 10, corners: [.topLeft, .topRight]))
+ .foregroundColor(Color(labels[index].color))
+ .background(Color(labels[index].color).opacity(0.23), in: RoundedCorner(radius: 10, corners: [.topLeft, .topRight]))
}
} else {
Rectangle()
@@ -675,7 +680,7 @@ struct ImportDataView: View {
importData()
} else {
showToast = true
- toastMessage = "Unlinked Categories"
+ toastMessage = String(localized: "Unlinked Categories")
}
} else if progress > 5 {
@@ -691,7 +696,7 @@ struct ImportDataView: View {
guard sample.containsDigits else {
showToast = true
- toastMessage = "Invalid Column"
+ toastMessage = String(localized: "Invalid Column")
return
}
}
@@ -701,7 +706,7 @@ struct ImportDataView: View {
guard validateDoubles(strings: stringColumn) else {
showToast = true
- toastMessage = "Invalid Column"
+ toastMessage = String(localized: "Invalid Column")
return
}
}
@@ -716,7 +721,7 @@ struct ImportDataView: View {
if progress < 5 {
guard !remainingColumns.isEmpty else {
showToast = true
- toastMessage = "Insufficient Columns"
+ toastMessage = String(localized: "Insufficient Columns")
return
}
selectedColumn = remainingColumns[0]
@@ -778,7 +783,7 @@ struct ImportDataView: View {
if file.startAccessingSecurityScopedResource() {
guard let message = try String(data: Data(contentsOf: file), encoding: .utf8) else {
showToast = true
- toastMessage = "Invalid File"
+ toastMessage = String(localized: "Invalid File")
return
}
@@ -840,7 +845,7 @@ struct ImportDataView: View {
func processCSV() {
guard data.containsDigits else {
showToast = true
- toastMessage = "Invalid File"
+ toastMessage = String(localized: "Invalid File")
return
}
@@ -852,7 +857,7 @@ struct ImportDataView: View {
guard !holdingRows.isEmpty else {
showToast = true
- toastMessage = "Invalid File"
+ toastMessage = String(localized: "Invalid File")
return
}
@@ -865,7 +870,7 @@ struct ImportDataView: View {
//
guard maxColumnCount > 3 else {
showToast = true
- toastMessage = "Invalid File"
+ toastMessage = String(localized: "Invalid File")
return
}
@@ -909,17 +914,17 @@ struct ImportDataView: View {
_ = dataController.newTransaction(note: row[noteColumnIndex], category: rowCategory, income: rowCategory.income, amount: abs(transactionAmount), date: transactionDate, repeatType: 0, repeatCoefficient: 1, delay: false)
} else {
processingState = .error
- errorMessage = "Invalid values in amount column."
+ errorMessage = String(localized: "Invalid values in amount column.")
return
}
} else {
processingState = .error
- errorMessage = "Error occurred while matching categories."
+ errorMessage = String(localized: "Error occurred while matching categories.")
return
}
} else {
processingState = .error
- errorMessage = "Invalid dates in date column."
+ errorMessage = String(localized: "Invalid dates in date column.")
return
}
}
diff --git a/app/dime/Views/InsightsView.swift b/app/dime/Views/InsightsView.swift
index 8e5b1f6..c301ac7 100644
--- a/app/dime/Views/InsightsView.swift
+++ b/app/dime/Views/InsightsView.swift
@@ -21,11 +21,11 @@ struct InsightsView: View {
var chartTypeString: String {
if chartType == 1 {
- return "week"
+ return String(localized: "week")
} else if chartType == 2 {
- return "month"
+ return String(localized: "month")
} else if chartType == 3 {
- return "year"
+ return String(localized: "year")
} else {
return ""
}
diff --git a/app/dime/Views/LogView.swift b/app/dime/Views/LogView.swift
index 5da5075..fad77f8 100644
--- a/app/dime/Views/LogView.swift
+++ b/app/dime/Views/LogView.swift
@@ -493,11 +493,11 @@ struct LogInsightsView: View {
var headingText: String {
if insightsType == 1 {
- return "Net total"
+ return String(localized: "Net total")
} else if insightsType == 2 {
- return "Earned"
+ return String(localized: "Earned")
} else {
- return "Spent"
+ return String(localized: "Spent")
}
}
@@ -505,7 +505,7 @@ struct LogInsightsView: View {
VStack(spacing: -3) {
VStack(spacing: 2) {
HStack(spacing: 4) {
- Text(LocalizedStringKey(headingText))
+ Text(headingText)
.font(.system(.body, design: .rounded).weight(.medium))
.foregroundColor(Color.PrimaryText.opacity(0.9))
Button {
@@ -1340,7 +1340,7 @@ struct SingleTransactionView: View {
}
.offset(x: offset)
.accessibilityElement(children: .ignore)
- .accessibilityLabel("\(transaction.wrappedNote), \(currencySymbol)\(String(format: "%.2f", transaction.wrappedAmount)), Transaction Category: \(transaction.category?.wrappedName ?? "Unknown"), Transaction made at \(timeConverterAccessibilityLabel(date: transaction.wrappedDate))")
+ .accessibilityLabel("\(transaction.wrappedNote), \(currencySymbol)\(String(format: "%.2f", transaction.wrappedAmount)), Transaction Category: \(transaction.category?.wrappedName ?? String(localized: "Unknown")), Transaction made at \(timeConverterAccessibilityLabel(date: transaction.wrappedDate))")
}
.onChange(of: deletePopup) { _ in
if deletePopup {
@@ -2089,7 +2089,7 @@ struct WeekStepperView: View {
let endComponents = DateComponents(day: 7, second: -1)
let endWeekDate = Calendar.current.date(byAdding: endComponents, to: showingDate) ?? Date.now
- return "showing transactions from " + dateFormatter.string(from: showingDate) + " to " + dateFormatter.string(from: endWeekDate)
+ return String(localized: "showing transactions from \(dateFormatter.string(from: showingDate)) to \(dateFormatter.string(from: endWeekDate))")
}
var body: some View {
@@ -2240,15 +2240,15 @@ func dateConverterAccessibilityLabel(date: Date) -> String {
let calendar = Calendar.current
if calendar.isDateInToday(date) {
- return "today"
+ return String(localized: "today")
} else if calendar.isDateInYesterday(date) {
- return "yesterday"
+ return String(localized: "yesterday")
} else {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "EEE, d MMM yyyy"
- return "on " + dateFormatter.string(from: date)
+ return String(localized: "on \(dateFormatter.string(from: date))")
}
}
diff --git a/app/dime/Views/NewBudgetView.swift b/app/dime/Views/NewBudgetView.swift
index 902100b..8d3e7c2 100644
--- a/app/dime/Views/NewBudgetView.swift
+++ b/app/dime/Views/NewBudgetView.swift
@@ -42,7 +42,7 @@ struct BrandNewBudgetView: View {
var initialProgress: Double
@State var showToast: Bool = false
- @State var toastMessage: String = "Missing Category"
+ @State var toastMessage: String = String(localized: "Missing Category")
// stage one (ignore if editing), overall budget or category budget
@State var categoryBudget: Bool = false
@@ -114,7 +114,8 @@ struct BrandNewBudgetView: View {
numberFormatter.maximumFractionDigits = 0
- return "~" + (numberFormatter.string(from: NSNumber(value: average)) ?? "$0") + " /day"
+ let formattedAverage = numberFormatter.string(from: NSNumber(value: average)) ?? "$0"
+ return String(localized: "~\(formattedAverage) /day")
}
// height of pickers
@@ -142,11 +143,26 @@ struct BrandNewBudgetView: View {
var instructions: [InstructionHeadings] {
[
- InstructionHeadings(title: "Indicate budget type", subtitle: "The overall budget tracks expenses across the board, while categorical budgets are tied to expenses of a particular type only."),
- InstructionHeadings(title: "Select a category", subtitle: "Begin by linking this budget to an existing category."),
- InstructionHeadings(title: "Choose a time frame", subtitle: "The budget will periodically refresh according to your preference."),
- InstructionHeadings(title: "Pick a start date", subtitle: "Which day of the \(timeFrameString) do you want your budget to start from?"),
- InstructionHeadings(title: "Set budget amount", subtitle: "Try your best to stay under this limit! Also, feel free to change this in the future.")
+ InstructionHeadings(
+ title: String(localized: "Indicate budget type"),
+ subtitle: String(localized: "The overall budget tracks expenses across the board, while categorical budgets are tied to expenses of a particular type only.")
+ ),
+ InstructionHeadings(
+ title: String(localized: "Select a category"),
+ subtitle: String(localized: "Begin by linking this budget to an existing category.")
+ ),
+ InstructionHeadings(
+ title: String(localized: "Choose a time frame"),
+ subtitle: String(localized: "The budget will periodically refresh according to your preference.")
+ ),
+ InstructionHeadings(
+ title: String(localized: "Pick a start date"),
+ subtitle: String(localized: "Which day of the \(timeFrameString) do you want your budget to start from?")
+ ),
+ InstructionHeadings(
+ title: String(localized: "Set budget amount"),
+ subtitle: String(localized: "Try your best to stay under this limit! Also, feel free to change this in the future.")
+ )
]
}
@@ -543,7 +559,7 @@ struct BrandNewBudgetView: View {
Button {
if progress == 2 && selectedCategory == nil {
showToast = true
- toastMessage = "Missing Category"
+ toastMessage = String(localized: "Missing Category")
UINotificationFeedbackGenerator().notificationOccurred(.error)
return
}
@@ -709,7 +725,7 @@ struct BrandNewBudgetView: View {
if price == 0 {
UINotificationFeedbackGenerator().notificationOccurred(.error)
showToast = true
- toastMessage = "Missing Amount"
+ toastMessage = String(localized: "Missing Amount")
return
}
diff --git a/app/dime/Views/Settings/Settings Subviews/SettingsAppIconView.swift b/app/dime/Views/Settings/Settings Subviews/SettingsAppIconView.swift
index fbb066b..1ef5d9d 100644
--- a/app/dime/Views/Settings/Settings Subviews/SettingsAppIconView.swift
+++ b/app/dime/Views/Settings/Settings Subviews/SettingsAppIconView.swift
@@ -23,16 +23,16 @@ struct SettingsAppIconView: View {
let options: [AppIconBundle] = [
AppIconBundle(
actualFileName: "AppIcon1", exampleFileName: "AppIcon1_EG", displayName: "V2.0",
- displaySubtitle: "Designed by the brilliant @rudra_dsigns, check out his work on Twitter."),
+ displaySubtitle: String(localized: "Designed by the brilliant @rudra_dsigns, check out his work on Twitter.")),
AppIconBundle(
actualFileName: "AppIcon2", exampleFileName: "AppIcon2_EG", displayName: "Unicorn",
- displaySubtitle: "Dime definitely isn't becoming one but it never hurts to keep dreaming."),
+ displaySubtitle: String(localized: "Dime definitely isn't becoming one but it never hurts to keep dreaming.")),
AppIconBundle(
actualFileName: "AppIcon3", exampleFileName: "AppIcon3_EG", displayName: "V1.5",
- displaySubtitle: "An early prototype also designed by @rudra_dsigns that I kinda fancy."),
+ displaySubtitle: String(localized: "An early prototype also designed by @rudra_dsigns that I kinda fancy.")),
AppIconBundle(
actualFileName: "AppIcon4", exampleFileName: "AppIcon4_EG", displayName: "O.G.",
- displaySubtitle: "Haphazardly put together in under 30 minutes, the original Dime icon.")
+ displaySubtitle: String(localized: "Haphazardly put together in under 30 minutes, the original Dime icon."))
]
@State private var position: Int?
diff --git a/app/dime/Views/Settings/Settings Subviews/SettingsFeatureLabView.swift b/app/dime/Views/Settings/Settings Subviews/SettingsFeatureLabView.swift
index b3fe94c..5bf0c44 100644
--- a/app/dime/Views/Settings/Settings Subviews/SettingsFeatureLabView.swift
+++ b/app/dime/Views/Settings/Settings Subviews/SettingsFeatureLabView.swift
@@ -110,7 +110,7 @@ struct SettingsGoofyView: View {
}
@ViewBuilder
- func ToggleRow(text: String, bool: Binding, id: Int) -> some View {
+ func ToggleRow(text: LocalizedStringKey, bool: Binding, id: Int) -> some View {
HStack {
Text(text)
.font(.system(.body, design: .rounded))
diff --git a/app/dime/Views/Settings/SettingsView.swift b/app/dime/Views/Settings/SettingsView.swift
index 7eebdd3..9c01bd1 100644
--- a/app/dime/Views/Settings/SettingsView.swift
+++ b/app/dime/Views/Settings/SettingsView.swift
@@ -82,9 +82,9 @@ struct SettingsView: View {
}
@Environment(\.openURL) var openURL
- let supportEmail = SupportEmail(toAddress: "rafasohhh@gmail.com", subject: "Support Email")
+ let supportEmail = SupportEmail(toAddress: "rafasohhh@gmail.com", subject: String(localized: "Support Email"))
let featureRequestEmail = SupportEmail(
- toAddress: "rafasohhh@gmail.com", subject: "Feature Request")
+ toAddress: "rafasohhh@gmail.com", subject: String(localized: "Feature Request"))
@AppStorage("numberEntryType", store: UserDefaults(suiteName: "group.com.rafaelsoh.dime"))
var numberEntryType: Int = 2
@@ -498,7 +498,7 @@ struct SettingsView: View {
}
@ViewBuilder
- func ToggleRow(icon: String, color: String, text: String, bool: Bool, smaller: Bool = false, onTap: @escaping () -> Void)
+ func ToggleRow(icon: String, color: String, text: LocalizedStringKey, bool: Bool, smaller: Bool = false, onTap: @escaping () -> Void)
-> some View {
HStack(spacing: 12) {
Image(systemName: icon)
@@ -617,11 +617,11 @@ struct TipJarAlert: View {
var bottomCaption: String {
if unlockManager.failedTransaction {
- return "Tip failed to go through, please try again!"
+ return String(localized: "Tip failed to go through, please try again!")
} else if unlockManager.purchaseCount > 0 {
- return "Thanks a million, \(Image(systemName: "heart.fill")) Rafael"
+ return String(localized: "Thanks a million, ❤️ Rafael")
} else {
- return "Have a great day ahead!"
+ return String(localized: "Have a great day ahead!")
}
}
@@ -838,7 +838,7 @@ struct ProductView: View {
struct SettingsRowView: View {
var systemImage: String
- var title: String
+ var title: LocalizedStringKey
var colour: Int
var optionalText: String?
@@ -858,7 +858,7 @@ struct SettingsRowView: View {
)
.background(Color("\(colour)"), in: RoundedRectangle(cornerRadius: 6, style: .continuous))
- Text(LocalizedStringKey(title))
+ Text(title)
.font(.system(.body, design: .rounded).weight(.medium))
// .font(.system(size: 17, weight: .medium, design: .rounded))
diff --git a/app/dime/Views/TemplateTransactionView.swift b/app/dime/Views/TemplateTransactionView.swift
index bca7b73..d9b93cc 100644
--- a/app/dime/Views/TemplateTransactionView.swift
+++ b/app/dime/Views/TemplateTransactionView.swift
@@ -31,9 +31,9 @@ struct TemplateTransactionView: View {
var transactionTypeString: String {
if income {
- return "Income"
+ return String(localized: "Income")
} else {
- return "Expense"
+ return String(localized: "Expense")
}
}
@@ -132,13 +132,13 @@ struct TemplateTransactionView: View {
var repeatButtonAccessibility: String {
if repeatType == 1 {
- return "transaction recurs daily, button to edit recurring duration"
+ return String(localized: "transaction recurs daily, button to edit recurring duration")
} else if repeatType == 2 {
- return "transaction recurs weekly, button to edit recurring duration"
+ return String(localized: "transaction recurs weekly, button to edit recurring duration")
} else if repeatType == 3 {
- return "transaction recurs monthly, button to edit recurring duration"
+ return String(localized: "transaction recurs monthly, button to edit recurring duration")
} else {
- return "button to make transaction recurring"
+ return String(localized: "button to make transaction recurring")
}
}
@@ -649,20 +649,20 @@ struct TemplateTransactionView: View {
if transactionValue == 0 && category == nil {
toastImage = "questionmark.app"
- toastTitle = "Incomplete Entry"
+ toastTitle = String(localized: "Incomplete Entry")
showToast = true
generator.notificationOccurred(.error)
return
} else if transactionValue == 0 {
toastImage = "centsign.circle"
- toastTitle = "Missing Amount"
+ toastTitle = String(localized: "Missing Amount")
showToast = true
generator.notificationOccurred(.error)
return
} else if category == nil {
toastImage = "tray"
- toastTitle = "Missing Category"
+ toastTitle = String(localized: "Missing Category")
showToast = true
generator.notificationOccurred(.error)
return
diff --git a/app/dime/Views/TransactionView.swift b/app/dime/Views/TransactionView.swift
index 5945aaf..4da5f17 100644
--- a/app/dime/Views/TransactionView.swift
+++ b/app/dime/Views/TransactionView.swift
@@ -38,9 +38,9 @@ struct TransactionView: View {
var transactionTypeString: String {
if income {
- return "Income"
+ return String(localized: "Income")
} else {
- return "Expense"
+ return String(localized: "Expense")
}
}
@@ -90,13 +90,13 @@ struct TransactionView: View {
var repeatButtonAccessibility: String {
if repeatType == 1 {
- return "transaction recurs daily, button to edit recurring duration"
+ return String(localized: "transaction recurs daily, button to edit recurring duration")
} else if repeatType == 2 {
- return "transaction recurs weekly, button to edit recurring duration"
+ return String(localized: "transaction recurs weekly, button to edit recurring duration")
} else if repeatType == 3 {
- return "transaction recurs monthly, button to edit recurring duration"
+ return String(localized: "transaction recurs monthly, button to edit recurring duration")
} else {
- return "button to make transaction recurring"
+ return String(localized: "button to make transaction recurring")
}
}
@@ -991,7 +991,7 @@ struct TransactionView: View {
if price == 0 && category == nil {
toastImage = "questionmark.app"
- toastTitle = "Incomplete Entry"
+ toastTitle = String(localized: "Incomplete Entry")
showToast = true
toggleFieldColors()
@@ -1000,13 +1000,13 @@ struct TransactionView: View {
return
} else if price == 0 {
toastImage = "centsign.circle"
- toastTitle = "Missing Amount"
+ toastTitle = String(localized: "Missing Amount")
showToast = true
generator.notificationOccurred(.error)
return
} else if category == nil {
toastImage = "tray"
- toastTitle = "Missing Category"
+ toastTitle = String(localized: "Missing Category")
showToast = true
toggleFieldColors()
diff --git a/app/dime/Views/UpdateSheet.swift b/app/dime/Views/UpdateSheet.swift
index ebb63f7..f3af2e4 100644
--- a/app/dime/Views/UpdateSheet.swift
+++ b/app/dime/Views/UpdateSheet.swift
@@ -19,14 +19,14 @@ struct UpdateAlert: View {
@State var opacity = 0.0
let welcomeFeatures = [
- WelcomeSheetFeatureRow(icon: "appclip", header: "Siri Shorcuts", subtitle: "3 new Siri shortcuts allow you to conveniently add new transactions or access insights."),
- WelcomeSheetFeatureRow(icon: "arrow.down.doc.fill", header: "Data Import", subtitle: "Transfer pre-existing logs from other applications with a step-by-step guide."),
- WelcomeSheetFeatureRow(icon: "sun.haze.fill", header: "Future Transactions", subtitle: "With date restrictions lifted, log and view upcoming expenses/incomes."),
- WelcomeSheetFeatureRow(icon: "app.gift.fill", header: "App Icons", subtitle: "Choose from 3 new skeuomorphic icons beautifully crafted by the talented @rudra_dsigns."),
- WelcomeSheetFeatureRow(icon: "circle.grid.2x2.fill", header: "Re-designed Screens", subtitle: "Budget and category creation screens have been completely reworked."),
- WelcomeSheetFeatureRow(icon: "swatchpalette.fill", header: "Custom Category Colors", subtitle: "Using the stock iOS color picker, give your categories a long-awaited aesthetic refresh."),
- WelcomeSheetFeatureRow(icon: "exclamationmark.octagon.fill", header: "New Toasts", subtitle: "Similarly, alert toasts across the app have been re-designed."),
- WelcomeSheetFeatureRow(icon: "calendar", header: "Custom Time Frames", subtitle: "Change the start of a month's cycle to align with payday.")
+ WelcomeSheetFeatureRow(icon: "appclip", header: String(localized: "Siri Shortcuts"), subtitle: String(localized: "3 new Siri shortcuts allow you to conveniently add new transactions or access insights.")),
+ WelcomeSheetFeatureRow(icon: "arrow.down.doc.fill", header: String(localized: "Data Import"), subtitle: String(localized: "Transfer pre-existing logs from other applications with a step-by-step guide.")),
+ WelcomeSheetFeatureRow(icon: "sun.haze.fill", header: String(localized: "Future Transactions"), subtitle: String(localized: "With date restrictions lifted, log and view upcoming expenses/incomes.")),
+ WelcomeSheetFeatureRow(icon: "app.gift.fill", header: String(localized: "App Icons"), subtitle: String(localized: "Choose from 3 new skeuomorphic icons beautifully crafted by the talented @rudra_dsigns.")),
+ WelcomeSheetFeatureRow(icon: "circle.grid.2x2.fill", header: String(localized: "Re-designed Screens"), subtitle: String(localized: "Budget and category creation screens have been completely reworked.")),
+ WelcomeSheetFeatureRow(icon: "swatchpalette.fill", header: String(localized: "Custom Category Colors"), subtitle: String(localized: "Using the stock iOS color picker, give your categories a long-awaited aesthetic refresh.")),
+ WelcomeSheetFeatureRow(icon: "exclamationmark.octagon.fill", header: String(localized: "New Toasts"), subtitle: String(localized: "Similarly, alert toasts across the app have been re-designed.")),
+ WelcomeSheetFeatureRow(icon: "calendar", header: String(localized: "Custom Time Frames"), subtitle: String(localized: "Change the start of a month's cycle to align with payday."))
]
var body: some View {
@@ -103,12 +103,12 @@ struct UpdateAlert: View {
.offset(y: 2)
VStack(alignment: .leading, spacing: 3.5) {
- Text(LocalizedStringKey(row.header))
+ Text(row.header)
.font(.system(.body, design: .rounded).weight(.medium))
// .font(.system(size: 18, weight: .medium, design: .rounded))
.foregroundColor(Color.PrimaryText)
- Text(LocalizedStringKey(row.subtitle))
+ Text(row.subtitle)
.font(.system(.subheadline, design: .rounded).weight(.medium))
// .font(.system(size: 16, weight: .regular, design: .rounded))
// .lineSpacing(0.6)
diff --git a/app/dime/Views/WelcomeSheetView.swift b/app/dime/Views/WelcomeSheetView.swift
index 650859e..84d8d3a 100644
--- a/app/dime/Views/WelcomeSheetView.swift
+++ b/app/dime/Views/WelcomeSheetView.swift
@@ -27,9 +27,9 @@ struct WelcomeSheetView: View {
let timer = Timer.publish(every: 0.16, on: .main, in: .common).autoconnect()
let welcomeFeatures = [
- WelcomeSheetFeatureRow(icon: "list.bullet.rectangle.fill", header: "welcome_header_1", subtitle: "welcome_subtitle_1"),
- WelcomeSheetFeatureRow(icon: "chart.bar.xaxis", header: "welcome_header_2", subtitle: "welcome_subtitle_2"),
- WelcomeSheetFeatureRow(icon: "archivebox.fill", header: "welcome_header_3", subtitle: "welcome_subtitle_3")
+ WelcomeSheetFeatureRow(icon: "list.bullet.rectangle.fill", header: String(localized: "welcome_header_1"), subtitle: String(localized: "welcome_subtitle_1")),
+ WelcomeSheetFeatureRow(icon: "chart.bar.xaxis", header: String(localized: "welcome_header_2"), subtitle: String(localized: "welcome_subtitle_2")),
+ WelcomeSheetFeatureRow(icon: "archivebox.fill", header: String(localized: "welcome_header_3"), subtitle: String(localized: "welcome_subtitle_3"))
]
var body: some View {
@@ -66,11 +66,11 @@ struct WelcomeSheetView: View {
.offset(y: 2)
VStack(alignment: .leading, spacing: 5) {
- Text(LocalizedStringKey(welcomeFeatures[rowIndex].header))
+ Text(welcomeFeatures[rowIndex].header)
.font(.system(size: 18, weight: .medium, design: .rounded))
.foregroundColor(Color.PrimaryText)
- Text(LocalizedStringKey(welcomeFeatures[rowIndex].subtitle))
+ Text(welcomeFeatures[rowIndex].subtitle)
.font(.system(size: 16, weight: .regular, design: .rounded))
.fixedSize(horizontal: false, vertical: true)
.foregroundColor(Color.SubtitleText)