Skip to content

Commit f93e8bf

Browse files
committed
Allow a client to set a custom locale
Fixed some strings that didn't render in the correct locale Fixes #419 Fixes #325 Closes #373
1 parent 441c53a commit f93e8bf

File tree

13 files changed

+102
-32
lines changed

13 files changed

+102
-32
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,9 @@ Set whether the dialogs should vibrate the device when a selection is made. This
193193
* `dismissOnPause(boolean dismissOnPause)`
194194
Set whether the picker dismisses itself when the parent Activity is paused or whether it recreates itself when the Activity is resumed.
195195

196+
* `setLocale(Locale locale)`
197+
Allows the client to set a custom locale that will be used when generating various strings in the pickers. By default the current locale of the device will be used. Because the pickers will adapt to the Locale of the device by default you should only have to use this in very rare circumstances.
198+
196199
* `DatePickerDialog` `autoDismiss(boolean autoDismiss)`
197200
If set to `true` will dismiss the picker when the user selects a date. This defaults to `false`.
198201

library/src/main/java/com/wdullaer/materialdatetimepicker/date/DatePickerController.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.wdullaer.materialdatetimepicker.date;
1818

1919
import java.util.Calendar;
20+
import java.util.Locale;
2021
import java.util.TimeZone;
2122

2223
/**
@@ -57,6 +58,8 @@ public interface DatePickerController {
5758

5859
TimeZone getTimeZone();
5960

61+
Locale getLocale();
62+
6063
DatePickerDialog.Version getVersion();
6164

6265
DatePickerDialog.ScrollOrientation getScrollOrientation();

library/src/main/java/com/wdullaer/materialdatetimepicker/date/DatePickerDialog.java

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import com.wdullaer.materialdatetimepicker.TypefaceHelper;
5050
import com.wdullaer.materialdatetimepicker.Utils;
5151

52+
import java.text.DateFormatSymbols;
5253
import java.text.SimpleDateFormat;
5354
import java.util.Arrays;
5455
import java.util.Calendar;
@@ -102,6 +103,7 @@ public enum ScrollOrientation {
102103
private static final String KEY_TIMEZONE = "timezone";
103104
private static final String KEY_DATERANGELIMITER = "daterangelimiter";
104105
private static final String KEY_SCROLL_ORIENTATION = "scrollorientation";
106+
private static final String KEY_LOCALE = "locale";
105107

106108
private static final int ANIMATION_DURATION = 300;
107109
private static final int ANIMATION_DELAY = 500;
@@ -148,6 +150,7 @@ public enum ScrollOrientation {
148150
private Version mVersion;
149151
private ScrollOrientation mScrollOrientation;
150152
private TimeZone mTimezone;
153+
private Locale mLocale = Locale.getDefault();
151154
private DefaultDateRangeLimiter mDefaultLimiter = new DefaultDateRangeLimiter();
152155
private DateRangeLimiter mDateRangeLimiter = mDefaultLimiter;
153156

@@ -247,9 +250,9 @@ public void onCreate(Bundle savedInstanceState) {
247250
mDefaultView = savedInstanceState.getInt(KEY_DEFAULT_VIEW);
248251
}
249252
if (Build.VERSION.SDK_INT < 18) {
250-
VERSION_2_FORMAT = new SimpleDateFormat(activity.getResources().getString(R.string.mdtp_date_v2_daymonthyear), Locale.getDefault());
253+
VERSION_2_FORMAT = new SimpleDateFormat(activity.getResources().getString(R.string.mdtp_date_v2_daymonthyear), mLocale);
251254
} else {
252-
VERSION_2_FORMAT = new SimpleDateFormat(DateFormat.getBestDateTimePattern(Locale.getDefault(), "EEEMMMdd"), Locale.getDefault());
255+
VERSION_2_FORMAT = new SimpleDateFormat(DateFormat.getBestDateTimePattern(mLocale, "EEEMMMdd"), mLocale);
253256
}
254257
VERSION_2_FORMAT.setTimeZone(getTimeZone());
255258
}
@@ -289,6 +292,7 @@ public void onSaveInstanceState(@NonNull Bundle outState) {
289292
outState.putSerializable(KEY_SCROLL_ORIENTATION, mScrollOrientation);
290293
outState.putSerializable(KEY_TIMEZONE, mTimezone);
291294
outState.putParcelable(KEY_DATERANGELIMITER, mDateRangeLimiter);
295+
outState.putSerializable(KEY_LOCALE, mLocale);
292296
}
293297

294298
@Override
@@ -327,6 +331,12 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container,
327331
mTimezone = (TimeZone) savedInstanceState.getSerializable(KEY_TIMEZONE);
328332
mDateRangeLimiter = savedInstanceState.getParcelable(KEY_DATERANGELIMITER);
329333

334+
/*
335+
We need to update some variables when setting the locale, so use the setter rather
336+
than a plain assignment
337+
*/
338+
setLocale((Locale) savedInstanceState.getSerializable(KEY_LOCALE));
339+
330340
/*
331341
If the user supplied a custom limiter, we need to create a new default one to prevent
332342
null pointer exceptions on the configuration methods
@@ -565,10 +575,10 @@ private void updateDisplay(boolean announce) {
565575
if (mVersion == Version.VERSION_1) {
566576
if (mDatePickerHeaderView != null) {
567577
if (mTitle != null)
568-
mDatePickerHeaderView.setText(mTitle.toUpperCase(Locale.getDefault()));
578+
mDatePickerHeaderView.setText(mTitle.toUpperCase(mLocale));
569579
else {
570580
mDatePickerHeaderView.setText(mCalendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG,
571-
Locale.getDefault()).toUpperCase(Locale.getDefault()));
581+
mLocale).toUpperCase(mLocale));
572582
}
573583
}
574584
mSelectedMonthTextView.setText(MONTH_FORMAT.format(mCalendar.getTime()));
@@ -578,7 +588,7 @@ private void updateDisplay(boolean announce) {
578588
if (mVersion == Version.VERSION_2) {
579589
mSelectedDayTextView.setText(VERSION_2_FORMAT.format(mCalendar.getTime()));
580590
if (mTitle != null)
581-
mDatePickerHeaderView.setText(mTitle.toUpperCase(Locale.getDefault()));
591+
mDatePickerHeaderView.setText(mTitle.toUpperCase(mLocale));
582592
else
583593
mDatePickerHeaderView.setVisibility(View.GONE);
584594
}
@@ -974,6 +984,27 @@ public void setTimeZone(TimeZone timeZone) {
974984
DAY_FORMAT.setTimeZone(timeZone);
975985
}
976986

987+
/**
988+
* Set a custom locale to be used when generating various strings in the picker
989+
* @param locale Locale
990+
*/
991+
public void setLocale(Locale locale) {
992+
mLocale = locale;
993+
mWeekStart = Calendar.getInstance(mTimezone, mLocale).getFirstDayOfWeek();
994+
YEAR_FORMAT = new SimpleDateFormat("yyyy", locale);
995+
MONTH_FORMAT = new SimpleDateFormat("MMM", locale);
996+
DAY_FORMAT = new SimpleDateFormat("dd", locale);
997+
}
998+
999+
/**
1000+
* Return the current locale (default or other)
1001+
* @return Locale
1002+
*/
1003+
@Override
1004+
public Locale getLocale() {
1005+
return mLocale;
1006+
}
1007+
9771008
@SuppressWarnings("unused")
9781009
public void setOnDateSetListener(OnDateSetListener listener) {
9791010
mCallBack = listener;

library/src/main/java/com/wdullaer/materialdatetimepicker/date/DayPickerView.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ public void setController(DatePickerController controller) {
9696
mController.registerOnDateChangedListener(this);
9797
mSelectedDay = new MonthAdapter.CalendarDay(mController.getTimeZone());
9898
mTempDay = new MonthAdapter.CalendarDay(mController.getTimeZone());
99+
YEAR_FORMAT = new SimpleDateFormat("yyyy", controller.getLocale());
99100
refreshAdapter();
100101
onDateChanged();
101102
}
@@ -340,12 +341,12 @@ public void onInitializeAccessibilityEvent(@NonNull AccessibilityEvent event) {
340341
event.setItemCount(-1);
341342
}
342343

343-
private static String getMonthAndYearString(MonthAdapter.CalendarDay day) {
344+
private static String getMonthAndYearString(MonthAdapter.CalendarDay day, Locale locale) {
344345
Calendar cal = Calendar.getInstance();
345346
cal.set(day.year, day.month, day.day);
346347

347348
String sbuf = "";
348-
sbuf += cal.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault());
349+
sbuf += cal.getDisplayName(Calendar.MONTH, Calendar.LONG, locale);
349350
sbuf += " ";
350351
sbuf += YEAR_FORMAT.format(cal.getTime());
351352
return sbuf;
@@ -408,7 +409,7 @@ public boolean performAccessibilityAction(int action, Bundle arguments) {
408409
}
409410

410411
// Go to that month.
411-
Utils.tryAccessibilityAnnounce(this, getMonthAndYearString(day));
412+
Utils.tryAccessibilityAnnounce(this, getMonthAndYearString(day, mController.getLocale()));
412413
goTo(day, true, false, true);
413414
return true;
414415
}

library/src/main/java/com/wdullaer/materialdatetimepicker/date/MonthView.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,8 @@ public MonthView(Context context, AttributeSet attr, DatePickerController contro
154154
mController = controller;
155155
Resources res = context.getResources();
156156

157-
mDayLabelCalendar = Calendar.getInstance(mController.getTimeZone());
158-
mCalendar = Calendar.getInstance(mController.getTimeZone());
157+
mDayLabelCalendar = Calendar.getInstance(mController.getTimeZone(), mController.getLocale());
158+
mCalendar = Calendar.getInstance(mController.getTimeZone(), mController.getLocale());
159159

160160
mDayOfWeekTypeface = res.getString(R.string.mdtp_day_of_week_label_typeface);
161161
mMonthTitleTypeface = res.getString(R.string.mdtp_sans_serif);
@@ -318,7 +318,7 @@ public void setMonthParams(int selectedDay, int year, int month, int weekStart)
318318
// Figure out what day today is
319319
//final Time today = new Time(Time.getCurrentTimezone());
320320
//today.setToNow();
321-
final Calendar today = Calendar.getInstance(mController.getTimeZone());
321+
final Calendar today = Calendar.getInstance(mController.getTimeZone(), mController.getLocale());
322322
mHasToday = false;
323323
mToday = -1;
324324

@@ -394,7 +394,7 @@ protected int getMonthHeaderSize() {
394394

395395
@NonNull
396396
private String getMonthAndYearString() {
397-
Locale locale = Locale.getDefault();
397+
Locale locale = mController.getLocale();
398398
String pattern = "MMMM yyyy";
399399

400400
if (Build.VERSION.SDK_INT < 18) pattern = getContext().getResources().getString(R.string.mdtp_date_v1_monthyear);
@@ -557,7 +557,7 @@ protected boolean isHighlighted(int year, int month, int day) {
557557
* @return The weekday label
558558
*/
559559
private String getWeekDayLabel(Calendar day) {
560-
Locale locale = Locale.getDefault();
560+
Locale locale = mController.getLocale();
561561

562562
// Localised short version of the string is not available on API < 18
563563
if (Build.VERSION.SDK_INT < 18) {

library/src/main/java/com/wdullaer/materialdatetimepicker/date/SimpleMonthView.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,6 @@ public void drawMonthDay(Canvas canvas, int year, int month, int day,
5555
mMonthNumPaint.setColor(isHighlighted(year, month, day) ? mHighlightedDayTextColor : mDayTextColor);
5656
}
5757

58-
canvas.drawText(String.valueOf(day), x, y, mMonthNumPaint);
58+
canvas.drawText(String.format(mController.getLocale(), "%d", day), x, y, mMonthNumPaint);
5959
}
6060
}

library/src/main/java/com/wdullaer/materialdatetimepicker/date/YearPickerView.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ public View getView(int position, View convertView, ViewGroup parent) {
132132
}
133133
int year = mMinYear + position;
134134
boolean selected = mController.getSelectedDay().year == year;
135-
v.setText(String.valueOf(year));
135+
v.setText(String.format(mController.getLocale(),"%d", year));
136136
v.drawIndicator(selected);
137137
v.requestLayout();
138138
if (selected) {

library/src/main/java/com/wdullaer/materialdatetimepicker/time/AmPmCirclesView.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import com.wdullaer.materialdatetimepicker.Utils;
3131

3232
import java.text.DateFormatSymbols;
33+
import java.util.Locale;
3334

3435
/**
3536
* Draw the two smaller AM and PM circles next to where the larger circle will be.
@@ -73,7 +74,7 @@ public AmPmCirclesView(Context context) {
7374
mIsInitialized = false;
7475
}
7576

76-
public void initialize(Context context, TimePickerController controller, int amOrPm) {
77+
public void initialize(Context context, Locale locale, TimePickerController controller, int amOrPm) {
7778
if (mIsInitialized) {
7879
Log.e(TAG, "AmPmCirclesView may only be initialized once.");
7980
return;
@@ -107,7 +108,7 @@ public void initialize(Context context, TimePickerController controller, int amO
107108
Float.parseFloat(res.getString(R.string.mdtp_circle_radius_multiplier));
108109
mAmPmCircleRadiusMultiplier =
109110
Float.parseFloat(res.getString(R.string.mdtp_ampm_circle_radius_multiplier));
110-
String[] amPmTexts = new DateFormatSymbols().getAmPmStrings();
111+
String[] amPmTexts = new DateFormatSymbols(locale).getAmPmStrings();
111112
mAmText = amPmTexts[0];
112113
mPmText = amPmTexts[1];
113114

library/src/main/java/com/wdullaer/materialdatetimepicker/time/RadialPickerLayout.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,11 @@ public void setOnValueSelectedListener(OnValueSelectedListener listener) {
157157
/**
158158
* Initialize the Layout with starting values.
159159
* @param context A context needed to inflate resources
160+
* @param locale A Locale to be used when generating strings
160161
* @param initialTime The initial selection of the Timepicker
161162
* @param is24HourMode Indicates whether we should render in 24hour mode or with AM/PM selectors
162163
*/
163-
public void initialize(Context context, TimePickerController timePickerController,
164+
public void initialize(Context context, Locale locale, TimePickerController timePickerController,
164165
Timepoint initialTime, boolean is24HourMode) {
165166
if (mTimeInitialized) {
166167
Log.e(TAG, "Time has already been initialized.");
@@ -174,7 +175,7 @@ public void initialize(Context context, TimePickerController timePickerControlle
174175
mCircleView.initialize(context, mController);
175176
mCircleView.invalidate();
176177
if (!mIs24HourMode && mController.getVersion() == TimePickerDialog.Version.VERSION_1) {
177-
mAmPmCirclesView.initialize(context, mController, initialTime.isAM() ? AM : PM);
178+
mAmPmCirclesView.initialize(context, locale, mController, initialTime.isAM() ? AM : PM);
178179
mAmPmCirclesView.invalidate();
179180
}
180181

@@ -214,10 +215,10 @@ public boolean isValidSelection(int selection) {
214215
String[] secondsTexts = new String[12];
215216
for (int i = 0; i < 12; i++) {
216217
hoursTexts[i] = is24HourMode?
217-
String.format(Locale.getDefault(), "%02d", hours_24[i]) : String.format(Locale.getDefault(), "%d", hours[i]);
218-
innerHoursTexts[i] = String.format(Locale.getDefault(), "%d", hours[i]);
219-
minutesTexts[i] = String.format(Locale.getDefault(), "%02d", minutes[i]);
220-
secondsTexts[i] = String.format(Locale.getDefault(), "%02d", seconds[i]);
218+
String.format(locale, "%02d", hours_24[i]) : String.format(locale, "%d", hours[i]);
219+
innerHoursTexts[i] = String.format(locale, "%d", hours[i]);
220+
minutesTexts[i] = String.format(locale, "%02d", minutes[i]);
221+
secondsTexts[i] = String.format(locale, "%02d", seconds[i]);
221222
}
222223
// The version 2 layout has the hours > 12 on the inner circle rather than the outer circle
223224
// Inner circle and outer circle should be swapped (see #411)

0 commit comments

Comments
 (0)