16
\$\begingroup\$

I am currently using an enum in my Android application to display time periods:

  • Weekly
  • Bi-Weekly
  • Monthly
  • Quarterly
  • Yearly

I created the enum like this, because I wanted to know the description, and (roughly) number of days:

public enum SpendingPeriods {
    WEEKLY("Weekly", 7),
    BIWEEKLY("Bi-Weekly", 14),
    MONTHLY("Monthly", 30),
    QUARTERLY("Quarterly", 120),
    YEARLY("Yearly", 365);

    private final String description;
    private final int numDays;

    SpendingPeriods(String description, int numDays){
        this.description = description;
        this.numDays = numDays;
    }

    public String getDescription(){
        return description;
    }

    public int getNumDays(){
        return numDays;
    }
}

Now, I would like to localize the enum, and so far my only solution has been to remove the description from the constructor, and check Locale and switch based on number of days:

SpendingPeriods(int numDays){
        this.numDays = numDays;
        if(Locale.getDefault().getLanguage().equals("fr")){
            switch(numDays){
                case 7:
                    this.description = "Hebdomadaire";
                    break;
                case 14:
                    this.description="Bimensuel";
                    break;
                case 30:
                    this.description="Mensuel";
                    break;
                // Others
            }
        } else{
            // Fall back to English for unsupported languages
            switch(numDays){
                case 7:
                    this.description = "Weekly";
                    break;
                case 14:
                    this.description = "Bi-Weekly";
                    break;
                case 30:
                    this.description = "Monthly";
                    break;
                // Others
            }
        }
    }

I was hoping there would be a way to do this using a string-array in an XML file, but I can't seem to find anything like that. Is this okay practice? Is there a better way?

\$\endgroup\$
2
  • \$\begingroup\$ You can use properties files for simple configuration values too... \$\endgroup\$ May 17, 2015 at 18:05
  • \$\begingroup\$ @McAdam331 FYI, you shouldn't use titles like that in SO either. Titles should always be as descriptive as possible. \$\endgroup\$ May 17, 2015 at 21:17

2 Answers 2

17
\$\begingroup\$

Don't localize your Java code. You don't want to hand over your source code to your translator, and you don't want to recompile the code to add a support for a new language. Rather, you should internationalize your code and do all the localization through resources, as recommended in the Android Developers documentation.

Furthermore, localizing strings in isolation doesn't work in the general case. For example, "monthly" may need to be translated as « mensuel », « mensuelle », « mensuels », « mensuelles », or « mensuellement », depending on context. Word order also tends to differ between languages. Therefore, the only sane approach is to translate entire phrases at the point of use.

res/values/strings.xml

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <string name="expenses">Your {0,choice, 1#weekly| 2#bi-weekly| 3#monthly| 4#quarterly| 5#annual} expenses are {1,number,currency}.</string>
</resources>

res/values-fr/strings.xml

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <string name="expenses">Vos dépenses {0,choice, 1#hebdomadaires| 2#bimensuelles| 3#mensuelles| 4#trimestrielles| 5#annuelles} sont {1,number,currency}.</string>
</resources>

Java code

import java.text.*;
…

Format expensesFmt = new MessageFormat(getResources().getString(R.string.expenses));
textView.setText(expensesFmt.format(new Object[] { MONTHLY.ordinal(), 1337 }));

… to get

Your monthly expenses are $1337.00.

or

Vos dépenses mensuelles sont 1337,00€.
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Note that this allows me to save 156€ by simply switching the language. Thanks a bunch. :D:D:D But seriously, is there a way to check the resource for completeness, e.g., when adding BI_ANNUAL I'd like to know that the option is present in all XML files? \$\endgroup\$
    – maaartinus
    May 17, 2015 at 22:45
  • \$\begingroup\$ Thanks a lot, this was really well explained and is a lot cleaner than my current solution. I appreciate it \$\endgroup\$
    – AdamMc331
    May 17, 2015 at 23:09
3
\$\begingroup\$

It wasn't the focus of your question, but I'd like the point out that it's potentially dangerous to define time periods such as months or years as a fixed number of days. It will give you big head-aches, if you are actually trying to calculate reliable dates from these.

Instead consider using a date/time libray such as Joda-Time (also available as an Android-specific version) or the new Java 8 Time package (not yet available on Android). They allow you to correctly calculate with variable time periods.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ You're right, and when I create the objects I use Joda LocalDate objects to determine the actual starting/end dates, but I added the rough estimates because I wanted a way to order the enum values when displaying them, that is the only time they are used. Now that I said that out loud, I suppose I could have just sorted by SpendingPeriod.Ordinal()...... \$\endgroup\$
    – AdamMc331
    May 19, 2015 at 13:08
  • 2
    \$\begingroup\$ Great. In that case I'd recommend to rename the field numDays to something like order and document that you are using the approximate number of days for that. \$\endgroup\$
    – RoToRa
    May 19, 2015 at 13:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.